Displaying the First N Words of Announcement Bodies with XSL in a DVWP

I got a ping yesterday from someone who had come across one of my old posts about Displaying the First N Words of a Long Rich Text Column with XSL. While the bits and pieces are there in the post, without a decent knowledge of XSL, it wasn’t obvious to them how you’d actually using the XSL templates. 

In this case, the list in question was an Announcements list.  I whipped up the XSL below for a DVWP pretty quickly using the StripHTML and FirstNWords templates which I’ve made available in the SPXSLT Codeplex Project.  If you drop this into your XSL section, you should have something pretty close to what you want. I’ve got the number of words per announcement body set to 10 in line 36; you can change that to whatever you’d like.

If you have useful XSL templates which you’d like to share, post them to the Discussions over at the  SPXSLT Codeplex Project.

<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:template match="/">
		<xsl:call-template name="dvt_1"/>
	</xsl:template>

	<xsl:template name="dvt_1">
		<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
		<table border="0" width="100%" cellpadding="2" cellspacing="0">
			<xsl:for-each select="$Rows">
				<xsl:call-template name="dvt_1.rowview"/>
			</xsl:for-each>
		</table>
	</xsl:template>

	<xsl:template name="dvt_1.rowview">
		<xsl:variable name="BodyText">
			<xsl:call-template name="StripHTML">
				<xsl:with-param name="HTMLText" select="@Body"/>
			</xsl:call-template>
		</xsl:variable>
		<tr>
			<td class="ms-vb">
				<a href="{@FileRef}"><span class="ms-announcementtitle"><xsl:value-of select="@Title"/></span></a><br/>
				by <xsl:value-of select="@Author" disable-output-escaping="yes"/>
			</td>
			<td class="ms-vb">
				<xsl:value-of select="ddwrt:FormatDate(string(@Created), 1033, 5)"/>
			</td>
		</tr>
		<tr>
			<td class="ms-vb">
				<xsl:call-template name="FirstNWords">
					<xsl:with-param name="TextData" select="$BodyText"/>
					<xsl:with-param name="WordCount" select="10"/>
					<xsl:with-param name="MoreText" select="'...'"/>
				</xsl:call-template>
			</td>
		</tr>
	</xsl:template>

	<xsl:template name="StripHTML">
		<xsl:param name="HTMLText"/>
		<xsl:choose>
			<xsl:when test="contains($HTMLText, '&lt;')">
				<xsl:call-template name="StripHTML">
					<xsl:with-param name="HTMLText" select="concat(substring-before($HTMLText, '&lt;'), substring-after($HTMLText, '&gt;'))"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="$HTMLText"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template name="FirstNWords">
		<xsl:param name="TextData"/>
		<xsl:param name="WordCount"/>
		<xsl:param name="MoreText"/>
		<xsl:choose>
			<xsl:when test="$WordCount &gt; 1 and (string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, ' ')) &gt; 0)">
				<xsl:value-of select="concat(substring-before($TextData, ' '), ' ')" disable-output-escaping="yes"/>
				<xsl:call-template name="FirstNWords">
					<xsl:with-param name="TextData" select="substring-after($TextData, ' ')"/>
					<xsl:with-param name="WordCount" select="$WordCount - 1"/>
					<xsl:with-param name="MoreText" select="$MoreText"/>
				</xsl:call-template>
			</xsl:when>
			<xsl:when test="(string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, ' ')) &gt; 0)">
				<xsl:value-of select="concat(substring-before($TextData, ' '), $MoreText)" disable-output-escaping="yes"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="$TextData" disable-output-escaping="yes"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

</xsl:stylesheet>