Unquestionably, one of the most powerful features of SharePoint is the DataView web part (unfortunately, only accessible through SharePoint Designer 2007 or Frontpage 2003).
There's a particularly useful trick for SharePoint Designer outlined in the Microsoft Office Online Help for SharePoint which shows how to use "joined item subviews".
In this case, I wanted a view of most recent comments for the Discussion Database site template.
This wasn't as simple as I was hoping because the comments don't identify the parent topic by name, just by ID.
The steps to generate the custom view in SharePoint Designer are:
- Click Data View -> Insert Data View.
- right-click Discussions -> Copy and Modify
- Remove all fields except for ID, Parent Folder Id and Body.
- Change item and folder scope to RecursiveAll -> click OK. Call the new view "Comments".
- Follow the steps in the Microsoft article and call the new linked view Comments (with Parent).
- Open the linked view. Add "Topic" from the Discussions list by clicking Insert Selected Fields as ... -> Multiple Item View.
- Click Table -> Insert -> Column to the Right.
-
- Click in the newly created column. Highlight Body, Modified and Modified By from the Comments view and click Insert Selected Fields as ... -> Joined Subview. Select ID on the left and Parent Folder ID on the right -> OK.
- If you want to set default text, click on "Click to set the display text if no matching items are found" and type what you want displayed.
- Now the hard bit. Right-click on the Web Part and choose Web Part Properties. Edit the contents of the XSL Editor they way you want them. I used:
<xsl:stylesheet xmlns:xs="http://www.w3.org/2001/XMLSchema"
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="/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
xmlns:SharePoint="Microsoft.SharePoint.WebControls">
<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/Discussions/Rows/Row"/>
<table border="0" width="100%" cellpadding="2" cellspacing="0">
<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:variable name="dvt_RowCount" select="count($Rows)" />
<xsl:variable name="dvt_CommentCount" select="count(/dsQueryResponse/Comments/Rows/Row)" />
<xsl:variable name="dvt_NoComment" select="$dvt_RowCount = $dvt_CommentCount" />
<xsl:choose>
<xsl:when test="$dvt_NoComment">
<xsl:call-template name="dvt_1.empty" />
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="$Rows">
<xsl:call-template name="dvt_2"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="dvt_1.empty">
<tr>
<td class="ms-vb" style="padding: 3px">
There are no comments yet.
</td>
</tr>
</xsl:template>
<xsl:variable name="dvt_2_automode">0</xsl:variable>
<xsl:template name="dvt_2">
<xsl:variable name="dvt_StyleName">Table</xsl:variable>
<xsl:variable name="dvt_ParentRow" select="current()" />
<xsl:variable name="Rows" select="../../../Comments/Rows/Row[@ParentFolderId=$dvt_ParentRow/@ID]" />
<xsl:variable name="dvt_RowCount" select="count($Rows)" />
<xsl:variable name="dvt_IsEmpty" select="$dvt_RowCount = 0" />
<xsl:choose>
<xsl:when test="$dvt_IsEmpty" />
<!-- do nothing! -->
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="dvt_2.body">
<xsl:with-param name="Rows" select="$Rows[position() < 3]" />
<xsl:with-param name="dvt_ParentRow" select="$dvt_ParentRow" />
</xsl:call-template></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="dvt_2.body">
<xsl:param name="Rows" />
<xsl:param name="dvt_ParentRow" />
<tr>
<td class="ms-vb" style="padding: 3px">
<a>
<xsl:attribute name="href"><xsl:value-of select="@FileRef" /></xsl:attribute>
<xsl:value-of select="@Title" />
</a><br/>
<xsl:for-each select="$Rows">
<xsl:call-template name="dvt_2.rowview" />
</xsl:for-each>
</td>
</tr>
</xsl:template>
<xsl:template name="dvt_2.rowview">
<xsl:value-of select="@Body" disable-output-escaping="yes" />
—<xsl:value-of select="@Editor" disable-output-escaping="yes" /><br/>
<em><xsl:text> (</xsl:text>
<xsl:value-of select="ddwrt:FormatDateTime(string(@Modified), 1033, 'dddd, hh:mmtt')"/>
<xsl:text>)</xsl:text></em></br>
</xsl:template>
</xsl:stylesheet>
That's more or less it! I plan to use this technique to customize a lot of my Data Views.