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.

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

12 Comments

  1. Hi Marc, big fan of your work! Maybe you can help me… I have a fairly complicated dataview webpart that improves on the SharePoint 2007 Discussion board. I have a list containing 2 content types, Discussion Topic and Discussion Reply. I have a column named ParentID which is only used in Discussion Reply content types in order to store the ID of the parent.

    So, when you create a new discussion, a Discussion Topic content type is created. When you create a child, a querystring carries the ID of the parent and puts the ID into the ParentID field in the Discussion Reply.

    This allows me to create a veiw where Parent Discussion content types are grouped with all their children below them in the group (with a little expand/collapse javascript icon to show replies, as you would normally see in sharepoint grouping).

    I actually have 2 levels of replies, but technically, using this modle, i could have as many as i want. I have used an XSL recurrsion method to do a count of child items below the parent, and add that to child items (sub-replies) below each child item (this is for 2nd level replies). This allows me to count all replies to a discussion, including 1st and 2nd level replies. This works great.

    The problem i have is that i want to sort the list by the grouping of Discussion Topics wich includes the most recently modified reply. For example, if i reply to an old topic that is at the bottom of the list, i want the entire grouping (including all replies) for that topic to go to the top of the list. I cant figure out in XSL how to sort the Topics list (grouped) by the date of the most recently modified child in that topic.

    My closest attempt was when I was able to use a variable to capture the date of each topics most recently modified child. I was going to use this variable to determine sort order but i get a webpart error when i declair a variable after my for-each but before my sort.

    I know i can do this with a workflow by adding a filed to the parent which is updated with the current time each time a child is added to it, but that means i will have to give users edit permissions to eachother’s messages, otherwise the workflow will break without impersonation (which i cant do).

    Reply
    • Joe:

      I didn’t answer for a while because I was thinking about it a bit. I’m absolutely that what you want to do is possible, but I think it’ll take some work. You’ll need a recursive function that will traverse each thread and spit back the latest post date. Then you’ll be able to sort based on that value.

      I don’t think I have an example that’s close to this, but there are quite a few recursive templates in my SPXSLT Codeplex Project that you could look at for ideas.

      M.

      Reply
      • I tried this using a recursive function and it appeared that i was getting the most recently modified date for each topic, but i wasnt able to sort by the variable… i got a webpart error. Anyhow, ill keep at it and see what i come up with.

        thanks

        -Joe

        Reply
  2. How do you sort with grouping? For instance I want to sort a list by title but if an item is part of a group I like to show the group and all the items under it. Example:
    Item A
    Item B
    Group C
    Item1
    Item2
    Item2
    Item D
    etc

    By default if I group and sort, I get the following behavior:
    Item A
    Item B
    Item D
    Group C
    Item1
    Item2
    Item2

    Basically, all the groupings are at the botom.

    Reply
  3. Hi Marc,

    Nice post, very use full.

    How do we disable the sorting of column header in SharePoint 2010 list view web part? Can we did here in XSLT?

    Please let me know.

    Regards,
    Balakrishna M.

    Reply

Have a thought or opinion?