Viewing recent comments in Discussions

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:

  1. Click Data View -> Insert Data View.
  2. right-click Discussions -> Copy and Modify
  3. Remove all fields except for ID, Parent Folder Id and Body.
  4. Change item and folder scope to RecursiveAll -> click OK. Call the new view "Comments".
  5. Follow the steps in the Microsoft article and call the new linked view Comments (with Parent).
  6. Open the linked view. Add "Topic" from the Discussions list by clicking Insert Selected Fields as ... -> Multiple Item View.
  7. Click Table -> Insert -> Column to the Right.
  8. 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.
  9. 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.
  10. 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" />
        &#x2014;<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.