I’ve written quite a few recursive XSL templates recently, so I thought I’d do a post explaining what they are and how useful they can be. On my current project, we’re using many Lookup Columns in Content Types which are based on items in Custom Lists. These Lookup Columns also are almost all multi-select, meaning that the user can select zero to n of the values to categorize the item they are working with.
One of SharePoint’s quirks is how it then stores the values that the user has selected. Generally, it looks like this: value1;value2;value3. No problem, really, as long as you are OK with seeing the semicolon separated values in your displays. However, if any of the values contains an apostrophe character (‘ or '), it will be stored in the column as &#39;, like so: value1&#39;;value2;value3 (It’s actually that string without the “amp;” part, but I can’t get WordPress to let me show it without it converting to the ‘ character.) SharePoint natively knows how to handle this, but if you are displaying the column in a DVWP, you may want to do a little work yourself to clean things up, and this is where a recursive XSL template comes in. (Simply adding the disable-output-escaping=”yes” parameter will make the display look right, but here I want to use the values in the column for some filtering, so the &#39; is a problem.)
A recursive XSL template isn’t really all that different than a recursive function in any other language. The template can call itself based on some condition multiple times as long as it is capable of “unwinding” itself at the end of the process. In this example, we want to remove all of the &#39; strings and replace them with the ‘ character. We don’t know how many of these strings there might be, nor do we want to care about it; we want the template to take care of it for us.
The template below works like this. We call it, passing in the MultiSelectValue string that may or may not have the &#39; string in it. The xsl:choose has an xsl:when condition that is true if the &#39; string is present. If it is, we call the template again with the &#39; string snipped out (substring-before the string plus the apostrophe plus substring-after the string), and so on. Once there are no more &#39; strings, the template will “unwind”, passing out the final string we want each time.
<xsl:template name="FixEscapedChars"> <xsl:param name="MultiSelectValue"/> <xsl:variable name="Apostrophe">'</xsl:variable> <xsl:choose> <xsl:when test="contains($MultiSelectValue, '&#39;')"> <xsl:call-template name="FixEscapedChars"> <xsl:with-param name="MultiSelectValue" select="concat(substring-before($MultiSelectValue, '&#39;'), $Apostrophe, substring-after($MultiSelectValue, '&#39;')) "/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$MultiSelectValue"/> </xsl:otherwise> </xsl:choose> </xsl:template>
Note that you can handle other encoded characters by simply adding a new xsl:when clause for each to this template.