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>    
    
        <dt>    
            <a href="{$SafeLinkUrl}" class="title" onclick="GoToLink(this);return false;" target="_self">    
                <xsl:value-of select="@Title" />    
            </a>    
        </dt>    
        <dd>    
            <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>    
       </dd>     
    </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:
<div>   
     <span>a great answer</span>    
</div>
And we perform:
substring(@Answer, 25)
Then we'll get:
<div><span>a great answer</span>
</div>
You are now returning really bad HTML to the browser:
<dd>   
    <div>     
        <span>a great answe...    
</dd>
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, '<')"/>    
        <!-- Recurse through 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>     
        <dt>    
            <a href="{$SafeLinkUrl}" class="title" onclick="GoToLink(this);return false;" target="_self">    
                <xsl:value-of select="@Title" />    
            </a>    
        </dt>    
    
        <dd>    
            <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>    
       </dd>     
    </xsl:template>    
Summary
- Use substring to strip fields to a certain number of characters - so you don't return everything
- For HTML fields, add removeHtmlTags template and use call-template to get the result into an XSL variable first
 
   
             
            