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>

Similar Posts

28 Comments

  1. Hello Marc,
    thank you for sharing this. I also stumble upon the same problems with the wrong url: 9_.000.
    If i’m correct the link to the page is @FileRep, but where is this created?

    How can i make sure i’ll get the right url?

    Thanks in advance!

  2. Great post!
    What if I want to display the text formatted as Rich Text in the DVWP, but I still want to display only the first N words/characters – and not risking cutting of the “text” in the middle of a HTML tag (which can break my “Read more” tag…)?

  3. Hi, thanks for the great info.

    I’d like to apply a style to the web part (e.g., “Shaded” or “Boxed, no labels”). Any suggestions for applying a style?

    It took me a bit of work to get the XSL working, so granted, I’m by no means a developer. But once I did that, changing the styles didn’t seem to have an effect.

    Thanks

    1. Kenton:

      The styles just determine what markup SharePoint Designer creates at the outset. If you know what markup you want, the styles aren’t really all that helpful. Also, once you’ve manually changed the XSL, it’s always a bad idea to try to use any of the dialogs to change settings. It can either b reak things or cause SPD to crash.

      M.

  4. Hi Marc,

    Thanks for this post, I’ve been able to get it working pretty well. I just have 2 questions on minor things, and would appreciate it if you could help me reach a solution.

    1.) Before implementing the custom XSLT, i could click on the title of a post, view it, then click the back button, and return to the blog summary view (on my default.aspx page). Now, when I click on the title of a post then go to click back, it still works in Mozilla, but gives me an error message in IE9. Any idea why this might be? I didn’t make any other changes except implementing the custom XSLT from this blog post.

    2.) The default summary view has little calendar icons next to the blog post with the data it was published on- would you be able to provide the code for how to add that to the custom XSLT from above?

    If you can help me with either/both of these, that would be great.

    Thanks!

    Brandon

    1. Brandon:

      It’s really hard to say what the answer would be to either of your questions without digging into your code. My suggestion would be to deconstruct the default blog post page to see how it renders each of the elements you’re having issues with.

      M.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.