Friday, 22 February 2013

Handling Apostrophe and Ampersand in a URL using XSLT

My relationship with XSL (and XSL stylesheets / XSLT) could easily be described as turbulent... I think most other peoples could as well! Frequently I feel like smashing my monitor, throwing my keyword, kicking something, swearing, gnarling, and sometimes frothing at the mouth.

Recently I needed to format some data returned by the SharePoint's LVWP (List View Webpart), that included formatting some text into an argument used in a link. The text could contain apostrophes and ampersands, so I needed to replace the ' (for apostrophe) and & (for ampersand) with the their Hex equivalents, %27 and %26

[Side note] I needed to do this because the link I was creating was to another SharePoint page that had a URL filter webpart on it, which wouldn't handle the HTML codes for apostrophe and ampersand, but was happy with the Hex codes.

To do this, I pulled my hair out for a few hours, then used the following template;

<xsl:template name="formatUrl">
 <xsl:param name="text" />
 <xsl:variable name="apos">&amp;#39;</xsl:variable>
 <xsl:variable name="amp">&amp;amp;</xsl:variable>
 <xsl:variable name="Hapos">%27</xsl:variable>
 <xsl:variable name="Hamp">%26</xsl:variable>
 <xsl:choose>
  <xsl:when test="contains($text, $apos)">
   <xsl:variable name="fronttext" select="substring-before($text,$apos)">
   </xsl:variable>
   <xsl:variable name="endtext" select="substring-after($text,$apos)">
   </xsl:variable>       
   <xsl:call-template name="formatUrl">
    <xsl:with-param name="text" select="$fronttext" />
   </xsl:call-template>       
   <xsl:value-of select="$Hapos" />       
   <xsl:call-template name="formatUrl">
    <xsl:with-param name="text" select="$endtext" />
   </xsl:call-template>
  </xsl:when>
   <xsl:when test="contains($text, $amp)">
   <xsl:variable name="fronttext" select="substring-before($text,$amp)">
   </xsl:variable>
   <xsl:variable name="endtext" select="substring-after($text,$amp)">
   </xsl:variable>       
   <xsl:call-template name="formatUrl">
    <xsl:with-param name="text" select="$fronttext" />
   </xsl:call-template>       
   <xsl:value-of select="$Hamp" />       
   <xsl:call-template name="formatUrl">
    <xsl:with-param name="text" select="$endtext" />
   </xsl:call-template>
  </xsl:when>     
  <xsl:otherwise>
   <xsl:value-of select="$text" disable-output-escaping="no" />
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

Call the template like this;

<xsl:variable name="title">
 <xsl:value-of disable-output-escaping="yes" select="@Title">
 </xsl:value-of>
</xsl:variable>

<xsl:variable name="sectionname">
   <xsl:call-template name="formatUrl">
     <xsl:with-param name="text" select="$title" />
   </xsl:call-template>
</xsl:variable>      

<a href="section.aspx?sectionname={$sectionname}" title="{@SomeOtherField}">
 <xsl:value-of disable-output-escaping="yes" select="@Title"/>
</a>


Happy XSLT'ing!