The XSL customizations of the XsltListViewWebPart in SharePoint 2010 are probably not a trivial thing. If you want to do something more complex with that the best starting top for reference materials is of course the SharePoint 2010 SDK – http://msdn.microsoft.com/en-us/library/ff604021.aspx. It provides extensive coverage on the topic, so I won’t repeat any of that in this posting. Here, I will concentrate on two things: the first one is a matter-of-fact issue, which is probably the first one that you will encounter when customizing the XsltListViewWebPart’s XSL – how to hook your custom XSL to the XsltListViewWebPart. The thing is that you have not just one but for options for that – the XsltListViewWebPart itself exposes two properties for setting the custom XSL – XsltListViewWebPart.Xsl and XsltListViewWebPart.XslLink and also the SPView class has two properties with the very same names and obviously the same purpose. Well, that’s bounty and to quickly answer the two questions that may already have arisen – first – what has the SPView class to do with the XsltListViewWebPart – the answer is simple: the two classes are really two representations of the same internal SharePoint being (check a previous posting of mine on the subject – http://stefan-stanev-sharepoint-blog.blogspot.com/2010/02/listviewwebpart-spview-two-sides-of.html). And the second question – if the two classes are indeed representations of one and the same thing do these two sets of properties map to the same internal properties too – the answer here is no, the “Xsl” and “XslLink” properties of the XsltListViewWebPart are really inherited from a base class (DataFormWebPart) that has no direct relation to list views and indeed the four properties are really independent from one another (and there are some differences in their treatment despite the matching names as you will see not more than). One vital thing here is that there is a point precedence for their treatment by the XsltListViewWebPart – the exact evaluation order is this:

  1. XsltListViewWebPart.XslLink
  2. XsltListViewWebPart.Xsl
  3. SPView.Xsl
  4. SPView.XslLink

Before starting with the exact specifics of by these properties I want to mention one other property of the XsltListViewWebPart class – CacheXslTimeOut. This is an integer property that specifies the cache time in seconds for the XslTransform object used by the XsltListViewWebPart. The caching of the XslTransform object is very useful because, of course, it boosts the performance. And the caching of the XslTransform also may be used or not used altogether depending on which of the “Xsl” or “XslLink” properties you use, which I reflect is vital to know beforehand. One other thing here – when I tested the “caching” behavior of these properties I any changed the value of the properties in the case of the “Xsl” ones or changed the underlying XSL file in the case of the “XslLink” properties. The immediate proposition of the exchange to the rendering of the web part doesn’t necessarily mean that the cache is not used because it may austerely mean that the exchange of the property invalidates the XslTransform cache. So in the small descriptions of the properties’ treatment not more than I won’t mention that the XslTransform cache is not applied but austerely that you see or don’t see immediately the exchange applied in the rendering of the XsltListViewWebPart. Of course for hard purposes you can always set the value of the CacheXslTimeOut property to 1 second so that you can quickly exchange the XSL and see the result immediately.

And now the details and specifics about the treatment of the “XSL” properties:

  • XsltListViewWebPart.XslLink – you can exchange this with any the SharePoint UI (it appears in the XsltListViewWebPart’s toolpart) or programmatically with the SharePoint object model. Note here that unlike the XslLink property of the SPView class you can’t specify austerely the name of a custom XSL file that resides in the system TEMPLATE\LAYOUTS\XSL folder (e.g. the standard main.xsl or a custom “custom.xsl”) – this won’t work (it may be a bit surprising). You have two options for specifying the path to your custom XSL file here – the first one is to specify a file under the TEMPLATE\LAYOUTS folder (it can be directly in that folder or any sub-folder not more than it, not just the “XSL” one) – and the path (rather URL in this case) should mandatorily start with “/_layouts/”. The other option is to reference an XSL file that resides on your site, for instance in a document library – then you can use any the site relation URL of the file or the server relation one. For example, if you have a “custom.xsl” in a library whose URL is “ID”, then the site relation URL will be “ID/custom.xsl” (no starting slash) and the server relation URL will be something like “/sites/mysite/ID/custom.xsl” (note the starting slash – the starting part of the URL depends on the server relation URL of your site). And about the caching behavior – fascinatingly enough it is different depending on whether you use an XSL file from the LAYOUTS folder or in a document library in the site – in the first case the changes to the referenced XSL file won’t be visible immediately, and in the second – they will be.
  • XsltListViewWebPart.Xsl – you can exchange this property with the object model, but the simpler way to do this is with the SharePoint Designer. With it it should be simple to exchange the Xsl property even without deep understanding of XSL – you can use the enhanced UI of the SharePoint Designer to modify the styling and rendering of individual list columns or to apply conditional rendering on whole rows in the XsltListViewWebPart. The SharePoint Designer involuntarily populates the Xsl property with an XSL snippet containing one or several XSL templates depending on your exact customizations (this XSL also references the standard “main.xsl” and the templates in it are rather “overrides” of the standard row and column rendering XSL templates). The changes to the “Xsl” property are applied immediately regardless of the value of the CacheXslTimeOut property. If you reflect that this may pose a performance issue for you, you can always save the XSL contained in the “Xsl” property to an external XSL file which you can then reference with the XsltListViewWebPart.XslLink or SPView.XslLink properties.
  • SPView.Xsl – you can again exchange this property programmatically – for that you will need to get the hidden SPView instance associated with your XsltListViewWebPart (see the link to my posting on the subject above) or again the simpler way to achieve that is to set the property in the view machinate in the “machinate.xml” file of your custom list template (custom “machinate.xml” files can also be specified in ListInstance feature elements via the “CustomSchema” attribute). Note that not more than the “View” element in the “machinate.xml” file you can have both “Xsl” and “XslLink” elements. One vital note – you should provide the XSL in the “Xsl” element in the “machinate.xml” and also in the SPView.Xsl property in an XML CDATA section. The changes to the SPView.Xsl property (those applied with code) are immediately visible in the XsltListViewWebPart regardless of the value of the CacheXslTimeOut property.
  • SPView.XslLink – you can exchange this property programmatically and also can set its value in the XslLink element in the view machinate in the “machinate.xml” file of your SharePoint list. Normally you provide only a file name in this property and the referenced XSL file with that name should exist in the system TEMPLATE\LAYOUTS\XSL folder. You can also reference files in sub-folders of the LAYOUTS\XSL folder and even files in the LAYOUTS folder itself – in the first case you set the “XslLink” property to “sub\custom.xsl” and in the second case – to “..\custom.xsl”. The XmlTransform caching is fully applied for the SPView.XslLink property depending on the value of the CacheXslTimeOut property. There is one superfluous thing here compared to the XsltListViewWebPart.XslLink property – if you set the CacheXslTimeOut property to 1 second you will need additionally to recycle the attention pool (which will force the withdrawal of the cache) and only after that you will see the changes to the underlying XSL file immediately in the rendering of the XsltListViewWebPart. This is also right if you have the CacheXslTimeOut  set to 1 second and you see the immediate changes but then set it to some higher value and then again reset it to 1 second – then you will no longer see the immediate changes in anticipation of you recycle the attention pool again. This means that the changing of the CacheXslTimeOut property itself doesn’t invalidate the caching of the XmlTransform in the case of the SPView.XslLink property.

So, this was the first topic that I wanted to talk about and about the second one I will demonstrate a small XSL snippet:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"

    xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:mycontrols="http://mycontrols" >

  <xsl:productivity method="html" indent="no"/>

  <xsl:decimal-format NaN=""/>

  <xsl:param name="XmlDefinition" select="."/>

 

  <xsl:template match="/">

    <xsl:value-of disable-productivity-escaping="yes" select="&lt;%@ Register Tagprefix=&quot;asp&quot; Namespace=&quot;mycontrols.WebControls&quot; Assembly=&quot;mycontrols, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d03859869fe4a098&quot; %&gt;"/>

    <mycontrols:MyControl runat="server" ListUrl="docs" />

 

    <table cellpadding="3">

      <tr>

        <xsl:for-each select="$XmlDefinition/ViewFields/FieldRef">

          <th><xsl:value-of select="@DisplayName"/></th>

        </xsl:for-each>

      </tr>

      <xsl:for-each select="/dsQueryResponse/Rows/Row">

        <tr>

          <xsl:variable name="row" select="." />

          <xsl:for-each select="$XmlDefinition/ViewFields/FieldRef">

            <xsl:variable name="fieldName" select="@Name" />

            <td>

             <xsl:choose>

                <xsl:when test="$fieldName=’LinkFilenameNoMenu’">

                  <xsl:value-of select="$row/@FileLeafRef"/>

                </xsl:when>

                <xsl:otherwise>

                  <xsl:value-of select="$row/@*[name() = $fieldName]" disable-productivity-escaping="yes"/>

                </xsl:otherwise>

              </xsl:choose>

            </td>

          </xsl:for-each>

        </tr>

      </xsl:for-each>

    </table>

  </xsl:template>

</xsl:stylesheet>

You can see in the snippet that it makes its own custom rendering of the underlying SharePoint list data (not very excellent at that) and doesn’t even include the standard SharePoint “vwstyles.xsl” and “fldtypes.xsl” (it’s only for demonstration purposes and should be as small as possible). The vital thing in it is in the very commencement of the body of its single XSL template classification – you can see there a somewhat concealed asp.net page “Register” directive and immediately after it an asp.net markup declaration of a server control. Note also that the “mycontrols” namespace of the server control element is declared in the root element of the XSL file. So, basically this means that you can place server controls inside the XSL and these will be instantiated by the XsltListViewWebPart and their logic will be executed server-side. As you see in the snippet I placed only one server control before the actual rendering of the list data, but you can place controls in every row or even cell that you render and you can provide some list item data to the properties of the server control or controls (there may be of course performance considerations because of the number of controls that can be made in this manner).

And to answer the question – how does the XsltListViewWebPart instantiate the server controls that you may place in the XSL. It is really simple – the XsltListViewWebPart uses the XSL transformation to produce HTML markup from the source XML, it then checks whether there are occurrences of the “runat=server” nominal inside the HTML markup: if there are no occurrences, the HTML markup is austerely rendered, otherwise the web part instantiates a server control by the asp.net TemplateControl.ParseControl method providing the raw HTML markup to its single parameter. The TemplateControl.ParseControl method as it name suggests parses asp.net markup and makes a server controls tree from it much like it happens when a normal “aspx” or “ascx” file gets compiled. So, with this small “trick” the XsltListViewWebPart allows you to place server controls and implement more complex server side logic inside your custom XSL. And one limitation to this deal with – you can’t use user controls (ascx files in the CONTROLTEMPLATES or LAYOUTS system folders) inside the XSL (server controls that use user controls internally with the TemplateControl.LoadControl method will also fail to instantiate their user controls).

Check it out:Stefan Stanev’s SharePoint blog