Unlocking the Mysteries of Data View Web Part XSL Tags – Part 6 – <xsl:variable>

This entry is part 6 of 21 in the series Unlocking the Mysteries of Data View Web Part XSL Tags

Cross-posted from EndUserSharePoint.com

<xsl:variable>

A value you create for use within a template which is only defined within the scope of that template.

Parameters and variables are used interchangeably, but how you create them is a bit different. While a parameter is a value which you expect to receive, a variable is something which you define. You refer to both of them with a preceding dollar sign once they are defined.

<xsl:variable> lets you create all sorts of values, from simple static values like:

<xsl:variable name="MyName" select="’Marc’"/>

to much more complex concepts like filtered, joined rowsets (this is a real example from a client project):

<xsl:variable name="Discipline" select="/dsQueryResponse/SDLC_Artifact_Groups/Rows/Row[@Title = (/dsQueryResponse/SDLC_Artifacts_2010/Rows/Row[ddwrt:AutoNewLine(string(@Title)) = current()/@Artifact_x0020_Name]/@Artifact_x0020_Group)]/@Discipline"/>

Most likely, as you’re getting up to speed with Data View Web Parts, you’re going to want to define relatively simple variables. All variables need to have:

  • A name – This is how you refer to the variable once you’ve created it, like $MyName or $Discipline
  • A value – You define the value either with a select or “within” the tag (more below).

Here are some relatively straightforward examples:

<xsl:variable name=”OnHand” select=”@Inventory + @Returned”/>
<xsl:variable name=”TotalCost” select=”sum(@Cost)”/>
<xsl:variable name=”RowNumber” select=”position()”/>

If we look at the example XSL again, we can see that there are <xsl:variable> tags used in a few places:

<XSL><xsl:stylesheet xmlns:x="<a href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</a>" xmlns:d="<a href="http://schemas.microsoft.com/sharepoint/dsp">http://schemas.microsoft.com/sharepoint/dsp</a>" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="<a href="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">http://schemas.microsoft.com/WebParts/v2/DataView/runtime</a>" xmlns:asp="<a href="http://schemas.microsoft.com/ASPNET/20">http://schemas.microsoft.com/ASPNET/20</a>" xmlns:__designer="<a href="http://schemas.microsoft.com/WebParts/v2/DataView/designer">http://schemas.microsoft.com/WebParts/v2/DataView/designer</a>" xmlns:xsl="<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">

  <xsl:output method="html" indent="no"/>
  <xsl:decimal-format NaN=""/>
  <xsl:param name="dvt_apos">'</xsl:param>
  <xsl:variable name="dvt_1_automode">0</xsl:variable>

  <xsl:template match="/">
    <xsl:call-template name="dvt_1"/>
  </xsl:template>

  <xsl:template name="dvt_1">
    <xsl:variable name="dvt_StyleName">Table</xsl:variable>
    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
    <table border="0" width="100%" cellpadding="2" cellspacing="0">
      <tr valign="top">
        <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
          <th width="1%" nowrap="nowrap"></th>
        </xsl:if>
        <th nowrap="nowrap">Title</th>
      </tr>
      <xsl:call-template name="dvt_1.body">
        <xsl:with-param name="Rows" select="$Rows"/>
      </xsl:call-template>
    </table>
  </xsl:template>

  <xsl:template name="dvt_1.body">
    <xsl:param name="Rows"/>
    <xsl:for-each select="$Rows">
      <xsl:call-template name="dvt_1.rowview"/>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="dvt_1.rowview">
    <tr>
      <xsl:if test="position() mod 2 = 1">
        <xsl:attribute name="class">ms-alternating</xsl:attribute>
      </xsl:if>
      <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
        <td width="1%" nowrap="nowrap">
          <span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
        </td>
      </xsl:if>
      <td>
        <xsl:value-of select="@Title"/>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet></XSL>

Here’s a description of the variables which we see above:

<xsl:variable name="dvt_1_automode">0</xsl:variable>

This defines a simple variable called dvt_1_automode with a value of “0”. I’m going to gloss over what this is used for, but note that rather than using the select attribute, you can also define the value of a variable “inside” the tag. This method is handy if you want to use some script to define a value.

<xsl:variable name="dvt_StyleName">Table</xsl:variable>

This is another simple text value being assigned to a variable. SharePoint Designer creates this variable to represent the layout type you are using for your DVWP. I’ve never seen it used in any way, and I generally remove it.

<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>

This is the single most important variable you will see in a DVWP. This is where we define a variable called Rows which represents the rowset we’ve gotten back from our DataSource. Note that the variable can be called Bob or Strawberry_Jam (note no spaces); Designer just uses the useful mnemonic Rows.

clip_image002It’s best from an efficiency perspective to add filters to the CAML so that you retrieve as few items as possible to meet your needs. When you set a filter in the Common Data View Tasks, that’s where the filter ends up: in the CAML. However, you may want to further filter the rowset more dynamically, like in the case where you’ve got a parameter on the Query String. When you want to do this more dynamic filtering, you can do it in the definition of the Rows like this:

<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row[@ID = $ID]"/>

Anything you place inside the brackets should evaluate to true or false: if the calculation returns true, the item is included in the rowset; if it returns false, the item is not included.

What you can calculate for the value of a variable is pretty much endless. One extremely useful set of functions is available in the ddwrt namespace. Why this isn’t documented more completely and visibly by Microsoft is beyond me, as some of these functions are useful all the time. Thank goodness for Serge van den Oever’s work on this or we would have nothing.

Next up: <xsl:for-each>

A way to iterate over a nodeset (group of rows).

Unlocking the Mysteries of Data View Web Part XSL Tags – Part 7 – <xsl:for-each>

This entry is part 7 of 21 in the series Unlocking the Mysteries of Data View Web Part XSL Tags

Cross-posted from EndUserSharePoint.com

<xsl:for-each>
A way to iterate over a nodeset (group of rows).

Once you have a rowset like the $Rows I talked about in the prior article about <xsl:variable>, you’ll want to do something with it. If you’ve ever used a report writer or created reports in an application like Microsoft Access, the basic constructs here may look a little familiar. Basically, you will want to have some sort of header and/or footer information (perhaps at multiple grouping levels) and then you’ll want to show some information from the detail rows. What you show in the detail rows generally comes from the items in the rowset, which we’ve defined as $Rows. (I’ll forego carrying forward my $Bob or $Strawberry_Jam examples to avoid confusion.)

Once again, let’s look at the basic example which I’ve been using in this series. (I keep including it just to make it simpler than flipping back and forth. I’m not fond of flipping back and forth.)

<XSL><xsl:stylesheet xmlns:x="<a href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</a>" xmlns:d="<a href="http://schemas.microsoft.com/sharepoint/dsp">http://schemas.microsoft.com/sharepoint/dsp</a>" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="<a href="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">http://schemas.microsoft.com/WebParts/v2/DataView/runtime</a>" xmlns:asp="<a href="http://schemas.microsoft.com/ASPNET/20">http://schemas.microsoft.com/ASPNET/20</a>" xmlns:__designer="<a href="http://schemas.microsoft.com/WebParts/v2/DataView/designer">http://schemas.microsoft.com/WebParts/v2/DataView/designer</a>" xmlns:xsl="<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">

  <xsl:output method="html" indent="no"/>
  <xsl:decimal-format NaN=""/>
  <xsl:param name="dvt_apos">'</xsl:param>
  <xsl:variable name="dvt_1_automode">0</xsl:variable>

  <xsl:template match="/">
    <xsl:call-template name="dvt_1"/>
  </xsl:template>

  <xsl:template name="dvt_1">
    <xsl:variable name="dvt_StyleName">Table</xsl:variable>
    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
    <table border="0" width="100%" cellpadding="2" cellspacing="0">
      <tr valign="top">
        <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
          <th width="1%" nowrap="nowrap"></th>
        </xsl:if>
        <th nowrap="nowrap">Title</th>
      </tr>
      <xsl:call-template name="dvt_1.body">
        <xsl:with-param name="Rows" select="$Rows"/>
      </xsl:call-template>
    </table>
  </xsl:template>

  <xsl:template name="dvt_1.body">
    <xsl:param name="Rows"/>
    <xsl:for-each select="$Rows">
      <xsl:call-template name="dvt_1.rowview"/>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="dvt_1.rowview">
    <tr>
      <xsl:if test="position() mod 2 = 1">
        <xsl:attribute name="class">ms-alternating</xsl:attribute>
      </xsl:if>
      <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
        <td width="1%" nowrap="nowrap">
          <span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
        </td>
      </xsl:if>
      <td>
        <xsl:value-of select="@Title"/>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet></XSL>

In the dvt_1 template, we set up the rowset variable, $Rows, and start outputting the TABLE which will contain the DVWP output. The next thing within the TABLE is a table row (TR) which contains a single table header cell (TH) with the text “Title”, which will be the header for the Title column. (Ignore the $dvt_1_automode stuff for now. I’ll get to things like that in a post at the end of this series.)

Next we call the dvt_1.body template. As I’ve mentioned before, the dvt_1.body template is generally where we’ll output summary information about the rowset, either before or after displaying the detail rows, depending on our requirements. Here we aren’t doing anything at the summary level, but we are calling dvt_1.rowview within an <xsl:for-each>.

What this does for us is to iterate over the set of rows, effectively calling dvt_1.rowview once for each list item in $Rows:

<xsl:for-each select="$Rows">
  <xsl:call-template name="dvt_1.rowview"/>
</xsl:for-each>

<xsl:for-each> only needs to have the select value, which should represent an XSL nodeset, or what I’ve been calling a rowset. (Yes, I probably use too many of these terms interchangeably. It comes from working with too many languages over the years and at the same time.)

Inside the <xsl:for-each> is also where you do any sorting with the <xsl:sort> tag. (You guessed it, that’s for the next article.)

Next up: <xsl:sort>
Used within an <xsl:for-each> to determine the sort order in which the nodeset (group of rows) are processed.

Unlocking the Mysteries of Data View Web Part XSL Tags – Part 8 – <xsl:sort>

This entry is part 8 of 21 in the series Unlocking the Mysteries of Data View Web Part XSL Tags

Cross-posted from EndUserSharePoint.com

<xsl:sort>
Used within an <xsl:for-each> to determine the sort order in which the nodeset (group of rows) are processed.

<xsl:sort> allows you to change the default sort order of the items as they are displayed in a Data View Web Part (DVWP).  By default (in almost all cases), the items will be displayed in ID number order. This is rarely useful, so in most cases you will want to indicate your own sort order.

<xsl:sort> is used within the <xsl:for-each>; tag.  This is because the sorting occurs on the entire rowset before the individual rows are displayed.

In the simple example we’ve been using, you don’t see an <xsl:sort>.  This is because when you first add a DVWP to the page, you haven’t yet specified a sort order:

<XSL><xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">

<xsl:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param name="dvt_apos">'</xsl:param>
<xsl:variable name="dvt_1_automode">0</xsl:variable>

<xsl:template match="/">
  <xsl:call-template name="dvt_1"/>
</xsl:template>

<xsl:template name="dvt_1">
  <xsl:variable name="dvt_StyleName">Table</xsl:variable>
  <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
  <table border="0" width="100%" cellpadding="2" cellspacing="0">
   <tr valign="top">
    <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
     <th class="ms-vh" width="1%" nowrap="nowrap"></th>
    </xsl:if>
    <th class="ms-vh" nowrap="nowrap">Title</th>
   </tr>
   <xsl:call-template name="dvt_1.body">
    <xsl:with-param name="Rows" select="$Rows"/>
   </xsl:call-template>
  </table>
</xsl:template>

<xsl:template name="dvt_1.body">
  <xsl:param name="Rows"/>
  <xsl:for-each select="$Rows">
   <xsl:call-template name="dvt_1.rowview"/>
  </xsl:for-each>
</xsl:template>

<xsl:template name="dvt_1.rowview">
  <tr>
   <xsl:if test="position() mod 2 = 1">
    <xsl:attribute name="class">ms-alternating</xsl:attribute>
  </xsl:if>
   <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
    <td class="ms-vb" width="1%" nowrap="nowrap">
     <span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
    </td>
   </xsl:if>
   <td class="ms-vb">
    <xsl:value-of select="@Title"/>
   </td>
  </tr>
</xsl:template>
</xsl:stylesheet></XSL>

If you do want to specify a sort order, you add the

within the , as I mentioned above. In this example, the rows (items) will just be sorted by the values in the Title column:

<xsl:template name="dvt_1.body">
  <xsl:param name="Rows"/>
  <xsl:for-each select="$Rows">
    <xsl:sort select="@Title" />
    <xsl:call-template name="dvt_1.rowview"/>
  </xsl:for-each>
</xsl:template>

In the simplest case, you just add the column(s) you want to sort by and you are all set.  However, there are several other attributes it’s important to know about:

Attribute Values Description
select XPath expression The select can take the form of any value XPath expression. Most often, you’ll just specify a column name.  Sometimes you may want to sort by a calculated value or a value in another list, and you can specify those expressions as well.
order [ascending | descending] This setting determines whether the sort is A-Z or Z-A.
data-type [text | number] Data-type lets you specify what type of value the select contains.  This is most often useful when you’d like to treat numbers as numbers rather than as text.
lang language-code Specify the language if you want the sort to be “language-aware”.
case-order [upper-first | lower-first] In the instance where the values are of mixed case, this setting identifies how to treat capital vs. lower case characters.

I’ve never had the need to specify the lang or case-order attributes myself, but it’s good to know about them.

You can have multiple <xsl:sort> tags in your <xsl:for-each>.  The <xsl:sort> tags are simply executed in order, giving you the ability to have primary, secondary, tertiary, etc., sorts.  For instance, the following example shows how you might generate a list of event attendees, sorted by LastName and then FirstName so that you could take attendance as people arrive:

<xsl:template name="dvt_1.body">
<xsl:param name="Rows"/>
<xsl:for-each select="$Rows">
<xsl:sort select="@LastName" />
<xsl:sort select="@FirstName" />
<xsl:call-template name="dvt_1.rowview"/>
</xsl:for-each>
</xsl:template>

clip_image002If you want to sort by a value that is in a different list, you need to specify the appropriate XPath expression.  At this point, you’re leaving the warm and comfy zone of the SharePoint Designer dialogs and you’ll need to write the XPath expression yourself.  Let’s say that you have two lists, one with one item per sale, and the other with total sales by region.  Assuming that you’ve set up your DataSource to contain both lists (you can have many more than two lists in a DVWP), the XPath expression might look something like this:

<xsl:sort select="/dsQueryResponse/List2/Rows/Row[@Region = current()/@Region]/@TotalSales" order="descending" />

This will display the individual sales sorted by the highest sales per region.

Next up:  <xsl:if>
A single conditional test. If the test is true, then the contained code is executed.

Unlocking the Mysteries of Data View Web Part XSL Tags – Part 9 – <xsl:if>

This entry is part 9 of 21 in the series Unlocking the Mysteries of Data View Web Part XSL Tags

Cross-posted from EndUserSharePoint.com

<xsl:if>
A single conditional test. If the test is true, then the contained code is executed.

<xsl:if> is one of the simple workhorses in the Data View Web Part (DVWP) XSL arsenal.  Its entire goal in life is to determine whether the code it contains is executed or not.

Looking at our standard, basic example DVWP code, we can see several <xsl:if>s in play:

<XSL><xsl:stylesheet xmlns:x="<a href="http://www.w3.org/2001/XMLSchema">http://www.w3.org/2001/XMLSchema</a>" xmlns:d="<a href="http://schemas.microsoft.com/sharepoint/dsp">http://schemas.microsoft.com/sharepoint/dsp</a>" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="<a href="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">http://schemas.microsoft.com/WebParts/v2/DataView/runtime</a>" xmlns:asp="<a href="http://schemas.microsoft.com/ASPNET/20">http://schemas.microsoft.com/ASPNET/20</a>" xmlns:__designer="<a href="http://schemas.microsoft.com/WebParts/v2/DataView/designer">http://schemas.microsoft.com/WebParts/v2/DataView/designer</a>" xmlns:xsl="<a href="http://www.w3.org/1999/XSL/Transform">http://www.w3.org/1999/XSL/Transform</a>" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">

<xsl:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param>'</xsl:param>
<xsl:variable>0</xsl:variable>

<xsl:template match="/">
<xsl:call-template/>
</xsl:template>

<xsl:template>
<xsl:variable>Table</xsl:variable>
<xsl:variable select="/dsQueryResponse/Rows/Row"/>
<table border="0" width="100%" cellpadding="2" cellspacing="0">
<tr valign="top">
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<th width="1%" nowrap="nowrap"></th>
</xsl:if>
<th nowrap="nowrap">Title</th>
</tr>
<xsl:call-template>
<xsl:with-param select="$Rows"/>
</xsl:call-template>
</table>
</xsl:template>

<xsl:template>
<xsl:param/>
<xsl:for-each select="$Rows">
<xsl:call-template/>
</xsl:for-each>
</xsl:template>

<xsl:template>
<tr>
<xsl:if test="position() mod 2 = 1">
<xsl:attribute>ms-alternating</xsl:attribute>
</xsl:if>
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<td width="1%" nowrap="nowrap">
<span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
</td>
</xsl:if>
<td>
<xsl:value-of select="@Title"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet></XSL>

Here’s what each of those <xsl:if>s is up to:

<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<th width="1%" nowrap="nowrap"></th>
</xsl:if>

imageIn this <xsl:if>, we’re testing the value of the $dvt_1_automode variable, and if it is ‘1’, then the contained code will be executed, which outputs a table header cell (TH). (This header cell will be shown if you turn on any of the Edit options in the Data View Properties, as shown.) I’ve never seen a cogent explanation for what the ddwrt:cf_ignore function does; if you know, please leave a comment!

<xsl:if test="position() mod 2 = 1">
<xsl:attribute>ms-alternating</xsl:attribute>
</xsl:if>

This <xsl:if> is checking to see if the current item is in an odd or even row.  (If you are unfamiliar with the modulus, or mod, function, it returns the remainder when you divide the first value by the second.)  The position() gives us the row number in the rowset.  If the row number is odd, we apply the ms-alternating CSS class.  This is the class that shows alternating white and light grey rows in List View Web Parts (LVWPs) in SharePoint out of the box.

image

Can you tell that I just downloaded SnagIt?

<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<td width="1%" nowrap="nowrap">
<span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
</td>
</xsl:if>

Finally, this <xsl:if> is checking once again for the value of $dvt_1_automode.  If it is enabled, the contained table detail cell (TD) is rendered. Once again, I’m not exactly sure about the ddwrt:am* functions used here. As I mentioned in a previous article in this series, the ddwrt namespace functions are woefully undocumented, other than in Serge van den Oever’s great article on MSDN.

The syntax for <xsl:if> is pretty simple.  Each time you use it, you need to specify a test which will evaluate to true or false. If the value is true, then the code the <xsl:if&gt; contains is executed, if the value is false, then it isn’t.

Next up: <xsl:choose>
Like <xsl:if>, but with multiple possibilities, more like if-then-else.

Unlocking the Mysteries of Data View Web Part XSL Tags – Part 10 – <xsl:choose>

This entry is part 10 of 21 in the series Unlocking the Mysteries of Data View Web Part XSL Tags

Cross-posted from EndUserSharePoint.com

<xsl:choose>
Like <xsl:if>, but with multiple possibilities, more like if-then-else.

<xsl:when>
Used within <xsl:choose> as a conditional test.  If the test is true, then the contained code is executed and the <xsl:choose> is exited.

<xsl:otherwise>
Used within <xsl:choose> as the “fall-back” condition. If none of the prior <xsl:when>s have been executed, the code contained here is executed.

I’m going to break with tradition on this post and talk about three XSL tags at once.  <xsl:choose>, <xsl:when>, and <xsl:otherwise> are sort of triplets anyway; they always travel together.

<xsl:choose> provides you a level of functionality which is more complex than <xsl:if>.  As I mention above, <xsl:choose> is more like the if-then-else construct that we’re all familiar with.  You can even have multiple <xsl:when>s to allow you to cover many different else conditions.

The most common way you’ll end up with an <xsl:choose> in your XSL is when you use the Conditional Formatting option in SharePoint Designer.  In the simplest case, you’ll be saying something like “If condition X is true, then do Y, else do Z”.  If you haven’t done any programming before, this might seem daunting, but it’s nothing different that the little deals we make with our kids: “Eat your dinner or you can’t have any dessert.”  Just the construction might be a little different.  So you’d say it like “If you eat dinner, then you get dessert, else you go to bed.”  You don’t have the threaten bedtime with an <xsl:choose>; you can just leave the <xsl:otherwise> empty.  (That case is effectively just what an <xsl:if> does.)

Enough with the abstract examples.  Say you want to display the Title of an item in bold if it starts with the letter “A”.  Perhaps not the most exciting example, but it should be simple to follow:

<xsl:choose>
<xsl:when test=”starts-with(@Title, 'A')”>
<b><xsl:value-of select=”@Title”/></b>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=”@Title”/>
</xsl:otherwise>
</xsl:choose>

So we’re rendering the value of the Title column whether it starts with “A” or not, but if it does start with “A”, we’re enclosing the value in the bold tags.  Simple enough, right?

Let’s look at a more complicated (and hopefully more useful) example.  I like to use DVWPs to provide dashboards.  No KPI lists for me; I like to do all the heavy lifting with the XSL.  Let’s say that we have a target sales goal of $1,000,000 for a sales region.   It’s a stretch goal, so we’re going to consider $750,000 good, too.  $500,000 is not so good; we’re going to have to take a good look at what’s going on there.  Anything less than $500,000 is just plain awful; heads are going to roll.

<xsl:choose>
<xsl:when test=”@Sales &gt; 1000000”>
<span style=”color:green; font-weight:bold;”><xsl:value-of select=”@Sales”/></span>
</xsl:when>
<xsl:when test=”@Sales &gt; 750000”>
<span style=”color:green;”><xsl:value-of select=”@Sales”/></span>
</xsl:when>
<xsl:when test=”@Sales &gt; 500000”>
<span style=”color:yellow;”><xsl:value-of select=”@Sales”/></span>
</xsl:when>
<xsl:otherwise>
<span style=”color:red;”><xsl:value-of select=”@Sales”/></span>
</xsl:otherwise>
</xsl:choose>

Here you can start to see the power of the <xsl:choose> construct.  You can “stack” the conditions in the order you’d like them to be evaluated.  As soon as one of the conditions evaluates to true, that <xsl:when>’s internal code is executed, and then the <xsl:choose> exits.  If *none* of the <xsl:when> conditions are met, then we ‘fall out” to the <xsl:otherwise> condition.  Keep in mind that, as I said above, you don’t have to have anything in the <xsl:otherwise> clause.

clip_image002Note that when we want to use certain characters in our XSL, we must “encode” them.  This is because those characters have special meaning in XSL.  These characters are:

  • < – The “less than sign” – &lt;
  • > -The “Greater than sign”  &gt;
  • “ – The “quote” character – &quot;
  • ‘ – The “apostrophe” character – &apos;
  • & – The “ampersand” character -&amp;

There’s really no other way to put it: dealing with this encoding is a real pain in the behind until you get used to it.  It’s also one of the big reasons why people see that dreaded “Unknown Error” when they start diving into the XSL.

Changing the color of text is just one simple example of what you can do.  The <xsl:when> clauses can contain calculations (“If I’m in the East Region, then my commission should be 25% of sales; if I’m in the Central Region, my commission should be 60% of gross profit;…”)

You’ll see that I’ve used the <xsl:value-of> tag above to output values, and yes you guessed it, I’ll go over that tag in the next article.

Next up: <xsl:value-of>
Outputs the value to which it evaluates, whether it be the value of a column, a variable, etc.