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, '<')"> <xsl:call-template name="StripHTML"> <xsl:with-param name="HTMLText" select="concat(substring-before($HTMLText, '<'), substring-after($HTMLText, '>'))"/> </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 > 1 and (string-length(substring-before($TextData, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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>
Worked a charm! Thanks
I’ve attempted to apply this to my Announcements web part in Sharepoint 2010 and it successfully truncates the text (thanks!) but breaks the links to the articles.
All the links are changed so that instead of:
http://blah.co.uk/_layouts/listform.aspx?PageType=4&ListId={D51A8968-509D-43D9-BD61-B4ACFBD080E3}&ID=9
it links to:
http://blah.co.uk/Lists/Group%20Announcements/9_.000
Any idea how I can truncate the body but leave the link alone?
Alex:
I’m not sure what’s going on here. Using the template for the Body won’t have any effect on the link on the Title column, so there must be something else that you’ve changed.
It’s tricky to post code here, but if you’d like me to take a look at your XSL, post it in the Discussions over at the SPXSLT Codeplex Project. I’ve got this template and many others available there.
Thanks,
M.
Hi Mark,
Thanks for replying so quickly!
I’ve had another play with the code and traced the issue to this bit of code that sets the link and title:
</span
The {@FileRef} variable is the one that produces the strange link with the number at the end so I crafted my own URL after looking at what the link should have been and just replaced the {@FileRef} part of the link.
All working absolutely fine now, thanks for the excellent code :)
Excellent! Glad you got things working the way you wanted them.
M.
Hi Alex, I’m having the same issue and would be interested in seeing your solution. Can you please share?
Thanks for the XSL, but i’m having the same issue. Also the “More announcements…” button is gone and my date isnt (Created date) is not showing anymore. Any ideas on this one?
Bram:
Adding the template alone wouldn’t cause the other changes you mention. It sounds like you may have inadvertanly removed some of the other XSL.
M.
Marc,
I have indeed changed a bit too mutch of the XSL. Now the only issue i’m having is that the links are not working fine, it is giving me 3_.000, as a link. While it should point to the article itself. You have any idea on this one?
Thanks.
I was too quick, still the same, can not get it to work properly. What am i doing wrong? I’m replacing the code and then the More Annoucements is gone, the Modify date or Create date is gone, and the links are broken.
Bram:
It’s really hard for me to say what the issue is without going through your XSL. I’ds suggest going back to the last known working state and trying the steps again.
M.
Marc,
I tried it several times, it is working, but i’m missing a lot of items. I tried combining the default.aspx file with the part you provided, but still can not get it to work. Is there a way i can edit the file with some other editor then the SharePoint Designer? Designer is very very slow and i rather use some other tool like notepad++ or Visual Studio.
Marc, i have solved the issue through the TechNet forum. The link with FileRef wasnt working properly, i made it a hard link with {@ID} (lists/listname/DispForm.aspx?ID={@ID} )
The link to More Announcements i will put that also as a hardlink, and then my problems are fixed. Thanks for you time and the great template you provided here!
Bram:
Glad you got it solved, whatever it was!
M.
Hi Marc, i tried your code and it works well if i limit the no of words to 25-30. if i need few more words to display say 50 or more, its giving me xslt error saying that “unresolved recursive templates are called”. kindly help me out, how to make it function for more than 50 words
Also i need to keep my formatting, as per my requirement and should not strip the html.
Geetha:
If you need to keep the formatting, you’ll need to write something yourself. Counting the words with the markup intact is an entirely more complicated task.
M.