Overview of XSLT List View Rendering System
Published: May 2010
This topic provides an overview of the system of list view rendering in Microsoft SharePoint Foundation. Before reading this topic, you should have at least a basic understanding of XSLT concepts, including style sheets, templates, parameters, node trees, and context node.
The XSLT style sheets that are included with SharePoint Foundation are located in .xsl files in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\LAYOUTS\XSL. The two most important of these files are vwsytles.xsl and fldtypes.xsl. The first of these files provides style sheets for rendering lists down to the level of rows. The second file provides style sheets for rendering particular fields—that is, cells—in the list views. A large set of global XSLT variables is defined in main.xsl.
An XSLT style sheet parses a source node tree in some XML language and produces a result node tree in a different XML language. In the simplest case, the source tree is transformed into the result tree. This is done by XSLT templates, each of which is a kind of rule that determines how a specific fragment of the source markup is transformed into a fragment of the result. However, it is not necessary for the transformation to simply re-express in the result language all (and only) the information of the source node tree. A transformation can exclude information from the source tree and insert information into the result that does not come from the source. In particular, an XSLT template can combine information from multiple input node trees. Each additional input node tree, besides the source node tree, is passed to a template as a parameter. The list view–rendering XSLT templates of SharePoint Foundation have two input node trees:
The source node tree is the View Schema markup that defines the current view of the list. It is this tree that the XSLT processor is parsing and traversing as it builds the result tree. Hence, at any given time during the XSLT transformation, the context node of the XSLT processor is a node in this markup.
The thisNode parameter tree is passed to each XSLT field rendering template by the calling template. This markup contains the actual data from the list. When a field is rendered, the actual field value is obtained from this parameter. For the full reference of the markup in the thisNode parameter, see dsQueryResponse XML.
For examples of these node trees, see Examples of Input and Result Node Trees in XSLT Transformations.
The hierarchy of XSLT templates in SharePoint Foundation is quite complex. The chain of calls to templates (via xsl:apply-templates and xsl:call-template) when a list view is being rendered varies depending on a variety of factors, including the type of list, which view of the list was selected, the view style, and whether the view includes grouping of rows, among others. This section describes the simplest possible chain of calls in the straightforward case when the user has navigated to a page with a list having the following characteristics.
The list is type 100 (generic).
The BaseViewID of the list is 1.
The view has view style 0 (basic table).
There is no grouping of rows.
The system of XSLT style sheets is invoked by the PreRender event of the page. The top level XSLT template is the unnamed template declared in vwsytles.xsl with the following start tag.
The behavior of this template depends on the outcome of some Boolean tests. However, in the most straightforward case, it calls xsl:apply-templates for templates in the RootTemplate mode and selects the current context node, which is the root of source node tree. (The XmlDefinition variable is defined in main.xsl as ".", the current context node.)
<xsl:apply-templates mode="RootTemplate" select="$XmlDefinition"/>
This applies the View_Default_RootTemplate template to the View element, which is the document element; that is, the top element of the source node tree. (See Examples of Input and Result Node Trees in XSLT Transformations for an example.) The following is the start tag for this template.
<xsl:template name="View_Default_RootTemplate" mode="RootTemplate" match="View" ddwrt:dvt_mode="root">
This template constructs the HTML <table> element that will render the list. It calls subsidiary templates using the following lines.
<xsl:apply-templates select="." mode="full"> <!-- child node omitted --> </xsl:apply-templates>
These lines call xsl:applytemplates for templates in the full mode and selects the current context mode, which at this point is still the View element. In the example scenario of a standard view of a generic list, the only matching template is the first one in the View Templates section of vwsytles.xsl. It has the following start tag.
<xsl:template match="View" mode="full">
This template begins rendering some of HTML details of the list. Most importantly, it calls additional templates using the following line.
<xsl:apply-templates select="." mode="RenderView" />
The only matching template is the one with following start tag.
<xsl:template match="View" mode="RenderView">
The call to this unnamed template differs from the earlier templates in the hierarchy in one important respect. The earlier templates used only the source node tree, which defines the list view, as a source of information. But to fill out the HTML table that will render the list requires information about this particular list, such as the number of items (rows) in it and the values of the particular fields in the list. Accordingly, this template is passed a parameter named thisNode, which contains the actual list data from the content database in the form of dsQueryResponse markup. Each subsequent call of a template, or application of the templates of a particular mode, passes this same parameter on to the called templates. For an example of the contents of a thisNode parameter, see Examples of Input and Result Node Trees in XSLT Transformations.
The template loops through all the rows (list items) in thisNode. For each, it applies templates with Item mode and passes them a reference to all the fields in the view. The following are some of the critical lines.
<xsl:for-each select="$AllRows"> <xsl:variable name="thisNode" select="."/> <!-- Matter omitted. The next lines run when the view does not include groups --> <xsl:apply-templates mode="Item" select="."> <xsl:with-param name="Fields" select="$Fields"/> <!-- matter omitted --> </xsl:apply-templates> <!-- matter omitted --> </xsl:for-each>
The AllRows variable is a reference to the Row elements in thisNode. Although it appears that the current node "." is being assigned to thisNode with the select attribute, this is actually just a default value that thisNode would have if nothing was passed for it to the template. In fact, the dsQueryResponse markup is passed as the parameter. For each row in the list, templates with mode Item are applied and are passed a Fields parameter. The latter is a reference to all the FieldRef elements in the source node tree.
There are several templates with mode Item, but only one matches the case in which the list type is 100 (generic) and the view style is 0. It is the very first template in the Row Templates section of vwstyles.xsl. It has the following start tag.
<xsl:template mode="Item" match="Row">
This template inserts the HTML <tr> start and end tags that render the row of the table for the current list item. In between, it loops through all the fields in the list item and applies to each templates of mode printTbleCellEcbAllowed. The following are the critical lines.
<tr> <!-- matter omitted --> <xsl:for-each select="$Fields"> <!-- matter omitted --> <xsl:apply-templates select="." mode="printTableCellEcbAllowed"> <xsl:with-param name="thisNode" select="$thisNode"/> </xsl:apply-templates> <!-- matter omitted --> </xsl:for-each> <!-- matter omitted --> </tr>
The only matching template has the following start tag.
<xsl:template name="FieldRef_printTableCell_EcbAllowed" match="FieldRef" mode="printTableCellEcbAllowed" ddwrt:dvt_mode="body">
This template inserts the HTML <td> start and end tags to form the cell of the table for the current field. It also assigns a cascading style sheets (CSS) class to the cell. In between the start tag and the end tag, it applies templates of mode PrintFieldWithECB, as shown here.
<td> <!-- matter omitted --> <xsl:apply-templates select="." mode="PrintFieldWithECB"> <!-- matter omitted --> </td>
The relevant matching template is found in fldtypes.xsl, as are all of the remaining templates in the hierarchy. It has the start tag shown at the top of the next code block. This template and the remaining ones in the chain render particular cells in the HTML table based on whether the current row is a header row or a data row, and based on type of the field (such as Note or Currency) and the base type of the field (such as Text or Number), and based on how the field should be rendered (for example, as plain text or as a link to the Display form). The following are start tags for the remaining templates for a Text field in a data row. Each is called by its predecessor either by name or as the result of an application of templates of a particular mode.
<xsl:template name="FieldRef_NoMenu_PrintFieldWithECB" ddwrt:ECB="Menu" match="FieldRef" mode="PrintFieldWithECB" ddwrt:ghost="always"> <xsl:template name="FieldRef_Ecb_PrintFieldWithDisplayFormLink" ddwrt:ECB="Link" match="FieldRef[@LinkToItem]" mode="PrintFieldWithDisplayFormLink" ddwrt:ghost="always"> <xsl:template name="FieldRef_PrintField" match="FieldRef" mode="PrintField" ddwrt:dvt_mode="body" ddwrt:ghost="always"> <xsl:template name="PrintField" ddwrt:dvt_mode="body" ddwrt:ghost="always"> <xsl:template name="FieldRef_Text_body" ddwrt:dvt_mode="body" match ="FieldRef" mode="Text_body">
The last of these is the template that finally renders the value of a Text field in the cell of the HTML table. The following is the entire markup for this template.
<xsl:template name="FieldRef_Text_body" ddwrt:dvt_mode="body" match ="FieldRef" mode="Text_body"> <xsl:param name="thisNode" select="."/> <xsl:choose> <xsl:when test="@AutoHyperLink='TRUE'"> <xsl:value-of select="$thisNode/@*[name()=current()/@Name]" disable-output-escaping ="yes"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$thisNode/@*[name()=current()/@Name]"/> </xsl:otherwise> </xsl:choose> </xsl:template>
Note that the template branches depending on whether the field is defined to automatically format strings that look like URLs as HTML <a> links. If it is, then when the XSLT processor renders the HTML for the field, it does not replace significant characters, such as "<" and "&", with their character entity equivalents (< and &), which a compliant XSLT processor would ordinarily do by default. Aside from this complication, the template simply emits the value of the field with the following line.
For a detailed discussion of this line, see How to: Customize the Rendering of a Field on a List View.