SharePoint - stripping HTML tags in XSL

Sometimes, when working with XSL (for example, in a content query webpart), you would like to limit the number of characters returned in a field in the template. 

Trimming field length in XSL

The itemstyle template may look something like this:

    <xsl:template name=“FAQ” match=“Row[@Style=‘FAQ’]” mode=“itemstyle”>       
        <xsl:variable name=“SafeLinkUrl”>
            <xsl:call-template name=“OuterTemplate.GetSafeLink”>
                <xsl:with-param name=“UrlColumnName” select=“‘LinkUrl’”/>
            </xsl:call-template>
        </xsl:variable>

       


           
                <xsl:value-of select=“@Title” />
           

       

       

            xsl:choose
                <xsl:when test=“string-length(@Answer) > 150”>
                    <xsl:value-of select=“concat(substring(@Answer,0,150),’…’)” disable-output-escaping=“yes”/>
                </xsl:when>
                xsl:otherwise
                    <xsl:value-of select=“@Answer” disable-output-escaping=“yes”/>
                </xsl:otherwise>
        </xsl:choose>
      

    </xsl:template>

The interesting part is where the @Answer field is rendered - if the length of this field is beyond 150 characters, it will return the first 150 characters and append an ellipsis (…)

Problem when we have a HTML field

The technique is pretty simple, but it is not fool proof - when the field you are trying to trim is an HTML / Rich field, you have a big problem - the trimming may suddenly cut off valid HTML, to return an invalid HTML.

Imagine, if the @Answer field was:

     a great answer

And we perform:

substring(@Answer, 25)

Then we’ll get:


     a great answe
r

You are now returning really bad HTML to the browser:

   
        a great answe...

See how the HTML isn’t terminated correctly with the proper end-tags.  If you are lucky, the browser guesses correctly and doesn’t break your page.  Many times though, it’s all down hill from here.

Using XSL to strip HTML tags from your field.

A very simple solution is to add an additional XSL template to strip out the HTML tags from your field before rendering it.  A simple version can be found on this article.

1.  Add this removeHtmlTags template in your XSL

<xsl:template name=“removeHtmlTags”>
    <xsl:param name=“html”/>
    xsl:choose
      <xsl:when test=“contains($html, ’<’)”>
        <xsl:value-of select=“substring-before($html, ’<’)”/>
       
        <xsl:call-template name=“removeHtmlTags”>
          <xsl:with-param name=“html” select=“substring-after($html, ’>’)”/>
        </xsl:call-template>
      </xsl:when>
      xsl:otherwise
        <xsl:value-of select=“$html”/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

2. Modify your ItemStyle to use the removeHtmlTags template in an XSL variable

    <xsl:template name=“FAQ” match=“Row[@Style=‘FAQ’]” mode=“itemstyle”>       
        <xsl:variable name=“SafeLinkUrl”>
            <xsl:call-template name=“OuterTemplate.GetSafeLink”>
                <xsl:with-param name=“UrlColumnName” select=“‘LinkUrl’”/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name=“textAnswer”>
            <xsl:call-template name=“removeHtmlTags”>
                <xsl:with-param name=“html” select=“@Answer” />
            </xsl:call-template>
        </xsl:variable>
       


           
                <xsl:value-of select=“@Title” />
           

       

       


            xsl:choose
                <xsl:when test=“string-length($textAnswer) > 150”>
                    <xsl:value-of select=“concat(substring($textAnswer,0,150),’…’)” disable-output-escaping=“yes”/>
                </xsl:when>
                xsl:otherwise
                    <xsl:value-of select=“$textAnswer” disable-output-escaping=“yes”/>
                </xsl:otherwise>
            </xsl:choose>
      

    </xsl:template>

Summary

  1. Use substring to strip fields to a certain number of characters - so you don’t return everything
  2. For HTML fields, add removeHtmlTags template and use call-template to get the result into an XSL variable first

Discussions