I hope someone can help me with this...
I am using SharePoint 2013 and trying to render a CQWP to show the latest blog posts. The problem I have is that when displaying the 'content' from the post I get ' ' added and quotes are shown as '"'. I have managed to strip the HTML mark up but can't seem to get rid of these.
My code is as follows - any help would be much appreciated, thanks.
Generate Summary and Remove HTML
<!-- Generate Summary -->
<xsl:template name="GenerateSummary">
<xsl:param name="Content"/>
<xsl:param name="Length"/>
<xsl:param name="Suffix"/>
<xsl:variable name="cleanContent">
<xsl:call-template name="RemoveHtml">
<xsl:with-param name="String" select="$Content"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="SubstringBeforeLast">
<xsl:with-param name="String"
select="substring($cleanContent, 1, $Length)"/>
<xsl:with-param name="Char" select="' '"/>
</xsl:call-template>
<xsl:if test="string-length($cleanContent) > $Length">
<xsl:value-of select="$Suffix"
disable-output-escaping="yes"/>
</xsl:if>
</xsl:template>
<!-- RemoveHTML -->
<xsl:template name="RemoveHtml">
<xsl:param name="String"/>
<xsl:choose>
<xsl:when test="contains($String, '<')">
<xsl:value-of select="substring-before($String, '<')"/>
<xsl:call-template name="RemoveHtml">
<xsl:with-param name="String"
select="substring-after($String, '>')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$String"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="SubstringBeforeLast">
<xsl:param name="String" />
<xsl:param name="Char" />
<xsl:param name="subsequent"/>
<xsl:choose>
<xsl:when test="contains($String, $Char)">
<xsl:if test="$subsequent = 1">
<xsl:value-of select="$Char"/>
</xsl:if>
<xsl:value-of select="substring-before($String, $Char)"/>
<xsl:call-template name="SubstringBeforeLast">
<xsl:with-param name="String"
select="substring-after($String, $Char)" />
<xsl:with-param name="Char" select="$Char" />
<xsl:with-param name="subsequent" select="1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$subsequent != 1">
<xsl:value-of select="$String"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Calling it here
<div class="fcItemContent">
<xsl:call-template name="GenerateSummary">
<xsl:with-param name="Content" select="#content" />
<xsl:with-param name="Length" select="200" />
<xsl:with-param name="Suffix" select="'...'"/>
</xsl:call-template>
</div>
Use function of XSLT
normalize-space()
**<xsl:value-of select="normalize-space()"/>**
White space is normalized by stripping leading and trailing white space and replacing sequences of white space characters with a single space. If the argument is omitted, the string-value of the context node is normalized and returned.
referred Link :
Remove Space using XSLT
Related
My thesis uses an APA citation. However, with research documents that is written in Thai, an inline citation must be of the form (firstname lastname, year) rather than the APA (lastname, year). This should be possible with a custom Microsoft Word 2013 bibliography style which would require an adjustment to the APA.XSL file in C:\Program Files (x86)\Microsoft Office\Office14\Bibliography\Style to include an additional logic similar to the follow:
<xsl:choose>
<xsl:when test="b:LCID='1054'">
(Firstname Lastname, year)
</xsl:when>
<xsl:otherwise>
(Lastname, year)
</xsl:otherwise>
</xsl:choose>
I believe that the additional logic should be added in this section, and that it must involve an adjustment to xsl:template formatNameCore.
<xsl:variable name="author0">
</xsl:variable>
However, my mind is drawing a blank beyond that. I wonder if anyone could point me to a correct direction. Help is much appreciated.
Here's the current xsl file.
After some more searching (and reading), I have stumbled upon this post in which all the temp1_prop_APA__ are specified as included below:
templ_prop_APA_MainAuthors_FML = %L, %f %m
templ_prop_APA_MainAuthors_FM = %f %m
templ_prop_APA_MainAuthors_ML = %L, %m
templ_prop_APA_MainAuthors_FL = %L, %f
Having nothing to lose; hence, I tried. While I do not know how exactly these %L, %F, or %M and their lowercase counterparts have came to be (explanations would have been nice), the expressions do work. In turn, included below is the section of adjusted code. So far, it seems to work for the purpose.
<xsl:template name="templ_prop_APA_CitationLong_FML" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%F %M %L'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%L, %F %M'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationLong_FM" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%F %M'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%F %M'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationLong_ML" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%M %L'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%L, %M'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationLong_FL" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%F %L'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%L, %F'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationShort_FML" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%F %M %L'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%L'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationShort_FM" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%F %M'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%F'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationShort_ML" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%M %L'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%L'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="templ_prop_APA_CitationShort_FL" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$_LCID='1054'">
<xsl:value-of select="'%F %L'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'%L'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Note: A full file is included here.
It has something to do with these templates:
<xsl:template name="templ_prop_APA_CitationShort_FML" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="/*/b:Locals/b:Local[#LCID=$_LCID]/b:APA/b:CitationShort/b:FML"/>
</xsl:template>
<!-- ... -->
<xsl:template name="templ_prop_APA_CitationShort_FL" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="/*/b:Locals/b:Local[#LCID=$_LCID]/b:APA/b:CitationShort/b:FL"/>
</xsl:template>
Try:
<xsl:template name="templ_prop_APA_CitationShort_FML" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="/*/b:Locals/b:Local[#LCID=$_LCID]/b:APA/b:CitationShort/b:FM"/>
<xsl:text> </xsl:text>
<xsl:value-of select="/*/b:Locals/b:Local[#LCID=$_LCID]/b:APA/b:CitationShort/b:FML"/>
</xsl:template>
<!-- ... -->
<xsl:template name="templ_prop_APA_CitationShort_FL" >
<xsl:param name="LCID" />
<xsl:variable name="_LCID">
<xsl:call-template name="localLCID">
<xsl:with-param name="LCID" select="$LCID"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="/*/b:Locals/b:Local[#LCID=$_LCID]/b:APA/b:CitationShort/b:FM"/>
<xsl:text> </xsl:text>
<xsl:value-of select="/*/b:Locals/b:Local[#LCID=$_LCID]/b:APA/b:CitationShort/b:FL"/>
</xsl:template>
I can't figure out where these values are getting populated, so this is the best I can do for now.
It seem safe to make this change here, instead of in the loop in <xsl:variable name="author0">...</xsl:variable>, as it's only ever called from there. This change won't affect your bibliography.
You may also have to modify the other temp1_prop_APA_*_* templates similarly.
I have this request coming in xml. Its a CDATA
<cmd>
<![CDATA[HG<><><36.75><0420>< ><HS6011201700446279><><>< >< >< ><><>< ><>< >< ><>< ><>< ><>]]>
</cmd>
I need to extract HS6011201700446279 from the cdata path.
Following is the regex they gave. How to use this in xsl
HG<\\s*><\\s*><.*><.*><.*><[A-Z]{2}(\\d{10,}).*
There is no regex support in XSLT 1.0. Assuming that the sub-string you want is within the 6th "tag" of the given string, you could extract it by calling a recursive named template:
<xsl:template match="cmd">
<result>
<xsl:call-template name="get-Nth-value">
<xsl:with-param name="list" select="."/>
<xsl:with-param name="N" select="6"/>
</xsl:call-template>
</result>
</xsl:template>
<xsl:template name="get-Nth-value">
<xsl:param name="list"/>
<xsl:param name="N"/>
<xsl:param name="delimiter" select="'><'"/>
<xsl:choose>
<xsl:when test="$N = 1">
<xsl:value-of select="substring-before(concat($list, $delimiter), $delimiter)"/>
</xsl:when>
<xsl:when test="contains($list, $delimiter) and $N > 1">
<!-- recursive call -->
<xsl:call-template name="get-Nth-value">
<xsl:with-param name="list" select="substring-after($list, $delimiter)"/>
<xsl:with-param name="N" select="$N - 1"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
Why cant I use this XSLT string function in a template?
<xsl:with-param name="text" select="substring($text,'2') and substring($text,1,(string-length($text)-1))" />
Here is the template:
<!-- Template to remove double quotes if available in first and last position of any field -->
<xsl:template name="remove-quotes">
<xsl:param name="text"/>
<xsl:param name="quot" select="'"'"/>
<xsl:param name="trim1" select="substring($text,'2')"/>
<xsl:param name="trim2" select="substring($text,1,(string-length($text)-1))"/>
<xsl:choose>
<xsl:when test="starts-with($text,$quot) and ends-with($text,$quot)">
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="$trim1 and $trim2"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Invoked by:
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="XXXXX"/>
</xsl:call-template>
I am not sure what your template is trying to do, but certainly this part makes no sense:
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="$trim1 and $trim2"/>
</xsl:call-template>
and is Boolean operator. An expression that contains and returns a result of either true() or false().
Same thing with:
<xsl:with-param name="text" select="substring($text,'2') and substring($text,1,(string-length($text)-1))" />
Added:
To remove either a leading or a trailing quote or both, you could do simply:
<xsl:variable name="lead" select="number(starts-with($text, '"'))" />
<xsl:variable name="trail" select="number(ends-with($text, '"'))" />
<xsl:value-of select="substring($text, 1 + $lead, string-length($text) - $lead - $trail)" />
XSLT Template:
<!-- Template to remove trailing and leading double quotes from the fields -->
<xsl:template name="remove-quotes">
<xsl:param name="text"/>
<xsl:param name="quot" select="'"'"/>
<xsl:param name="lead" select="number(starts-with($text, '"'))"/>
<xsl:param name="trail" select="number(ends-with($text, '"'))"/>
<xsl:choose>
<xsl:when test="starts-with($text,$quot) and ends-with($text,$quot)">
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="substring($text, 1 + $lead, string-length($text) - $lead - $trail)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Invoke like this:
<xsl:call-template name="remove-quotes">
<xsl:with-param name="text" select="SampleText"/>
</xsl:call-template>
I am quite new to XSLT,
I have a source XML message, which in its simplified version looks something like this:
<?xml version='1.0' encoding='iso-8859-1'?>
<Message>
<Invalid>
<InvalidBody>
<SynchError>
<ErrorText>The value of %1 should not be %2.</ErrorText>
<ErrorParameter>
<!-- Error Parameter is %1 identifier -->
<ErrorParameterType>value</ErrorParameterType>
<ErrorParameterValue>someField</ErrorParameterValue>
</ErrorParameter>
<ErrorParameter>
<!-- Error Parameter is %2 identifier -->
<ErrorParameterType>value</ErrorParameterType>
<ErrorParameterValue>someValue</ErrorParameterValue>
</ErrorParameter>
</SynchError>
</InvalidBody>
</Invalid>
</Message>
Now, I would like to use XSLT 1.0 to extract the ErrorText string and substitute the parameters %1 and %2 with the corresponding ErrorParameter/ErrorParameterValue values. The number of parameters %1, %2, %3... cannot be known in advance, so the solution should be flexible enough to accommodate a variable number of parameters.
Is there any elegant way to do this?
So, after quite a lot of googling around and a healthy dose of headache, I came up with the following solution, which seems to work like a charm:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:variable name="err-text" select="/Message/Invalid/InvalidBody/SynchError/ErrorText" />
<xsl:variable name="param-count" select="count(/Message/Invalid/InvalidBody/SynchError/ErrorParameter)" />
<xsl:call-template name="replace-params">
<xsl:with-param name="position" select="$param-count"/>
<xsl:with-param name="source-text" select="$err-text" />
</xsl:call-template>
</xsl:template>
<xsl:template name="replace-params">
<xsl:param name="position"/>
<xsl:param name="source-text"/>
<xsl:choose>
<xsl:when test="$position = 0">
<xsl:value-of select="$source-text"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="replace-params">
<xsl:with-param name="position" select="$position - 1"/>
<xsl:with-param name="source-text">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="$source-text" />
<xsl:with-param name="replace" select="concat('%', $position)" />
<xsl:with-param name="by" select="/Message/Invalid/InvalidBody/SynchError/ErrorParameter[$position]/ErrorParameterValue" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I use the "string-replace-all" template as a substitute for the XSLT 2.0 replace() function, since I cannot exclude multiple occurrences of a single parameter.
The "replace-params" template is applied recursively on the original text, iterating backwards on the index of the set of ErrorParameters.
The way I have tackled similar problems is to create a named template that recurses through the string (text element of) <ErrorText> with each cycle picking out the first n% item, then dereferences the <ErrorParameter> to access the contents of that and store in a result, then snip off the n% item just process and calls itself to grab the next one. When there are no more %n items left, return the result.
Here's an example of that, this template basically counts comma-separated items in a parameter passed in on the first cycle called List, and returns a $Count when it's finished.
<xsl:template name="CountList">
<xsl:param name="List"/>
<xsl:param name="Count" select="0"/>
<xsl:choose>
<xsl:when test="contains($List,',') = false()">
<xsl:value-of select="$Count"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="CountList">
<xsl:with-param name="List">
<xsl:value-of select="substring-after($List,',')"/>
</xsl:with-param>
<xsl:with-param name="Count">
<xsl:value-of select="$Count + 1"/>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
You can try something like this. You can use a replace instead of 'substring-before' and 'after' if this function is supported.
<xsl:template match="SynchError">
<xsl:apply-templates select="ErrorParameter[1]">
<xsl:with-param name="text"><xsl:value-of select="ErrorText"/></xsl:with-param>
<xsl:with-param name="position">1</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ErrorParameter">
<xsl:param name="text"/>
<xsl:param name="position"/>
<xsl:apply-templates select="following::ErrorParameter">
<xsl:with-param name="position"><xsl:value-of select="number($position)+1"/></xsl:with-param>
<xsl:with-param name="text"><xsl:value-of select="concat(substring-before($text,concat('%',$position)),ErrorParameterValue,substring-after($text,concat('%',$position)))"/></xsl:with-param>
</xsl:apply-templates>
<xsl:if test="not(following::ErrorParameter)">
<xsl:value-of select="concat(substring-before($text,concat('%',$position)),ErrorParameterValue,substring-after($text,concat('%',$position)))"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Here's another way you could look at it:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<output>
<xsl:call-template name="merge">
<xsl:with-param name="string" select="Message/Invalid/InvalidBody/SynchError/ErrorText"/>
<xsl:with-param name="parameters" select="Message/Invalid/InvalidBody/SynchError/ErrorParameter"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="merge">
<xsl:param name="string"/>
<xsl:param name="parameters"/>
<xsl:param name="flag" select="'%'"/>
<xsl:choose>
<xsl:when test="contains($string, $flag)">
<xsl:variable name="subsequent-char"
select="substring(translate(substring-after($string, $flag), '0123456789', ''), 1, 1)"/>
<xsl:variable name="i"
select="substring-before(substring-after($string, $flag), $subsequent-char)" />
<xsl:value-of select="substring-before($string, $flag)"/>
<xsl:value-of select="$parameters[number($i)]/ErrorParameterValue"/>
<!-- recursive call -->
<xsl:call-template name="merge">
<xsl:with-param name="string" select="substring-after($string, concat($flag, $i))"/>
<xsl:with-param name="parameters" select="$parameters"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I have a delimited string (delimited by spaces in my example below) that I need to tokenize, sort, and then join back together and I need to do all this using XSLT 1.0. How would I do that? I know I need to use xsl:sort somehow, but everything I’ve tried so far has given me some sort of error.
For example, if I run the code at the bottom of this posting, I get this:
strawberry blueberry orange raspberry
lime lemon
What would I do if I wanted to get this instead?:
blueberry lemon lime orange raspberry
strawberry
Note that I’m using XSLT 1.0.
Here is the code, which is based on code by Jeni Tennison.
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="tokenize1.xsl"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="'strawberry blueberry orange raspberry lime lemon'" />
</xsl:call-template>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="string" />
<xsl:param name="delimiter" select="' '" />
<xsl:choose>
<xsl:when test="$delimiter and contains($string, $delimiter)">
<token>
<xsl:value-of select="substring-before($string, $delimiter)" />
</token>
<xsl:text> </xsl:text>
<xsl:call-template name="tokenize">
<xsl:with-param name="string"
select="substring-after($string, $delimiter)" />
<xsl:with-param name="delimiter" select="$delimiter" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<token><xsl:value-of select="$string" /></token>
<xsl:text> </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Here's an inefficient pure version 1 solution:
<!-- Sort the tokens -->
<xsl:template name="sortTokens">
<xsl:param name="tokens" select="''"/> <!-- The list of tokens -->
<xsl:param name="separator" select="' '"/> <!-- What character separates the tokens? -->
<xsl:param name="pivot" select="''"/> <!-- A pivot word used to divide the list -->
<xsl:param name="lessThan" select="''"/> <!-- Accumulator for tokens less than the pivot (with leading separator) -->
<xsl:param name="moreThan" select="''"/> <!-- Accumulator for tokens more than the pivot (with leading separator) -->
<xsl:param name="leadWith" select="''"/> <!-- If set, output this before sorting -->
<xsl:param name="trailWith" select="''"/> <!-- If set, output this after sorting -->
<!-- The first token -->
<xsl:variable name="firstToken" select="substring-before(concat($tokens,$separator),$separator)"/>
<!-- Is the first token more or less than the pivot? -->
<xsl:variable name="pivotVsFirstToken">
<xsl:call-template name="compareStrings">
<xsl:with-param name="a" select="$pivot"/>
<xsl:with-param name="b" select="$firstToken"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<!-- No input, no output -->
<xsl:when test="$tokens = '' and $pivot = ''"></xsl:when>
<!-- At the outset, the first token becomes the pivot -->
<xsl:when test="$pivot = ''">
<xsl:value-of select="$leadWith"/>
<xsl:call-template name="sortTokens">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="tokens" select="substring-after($tokens,$separator)"/>
<xsl:with-param name="pivot" select="$firstToken"/>
</xsl:call-template>
<xsl:value-of select="$trailWith"/>
</xsl:when>
<!-- When all tokens are in a bucket, output the pivot between sorted buckets -->
<xsl:when test="$tokens = ''">
<xsl:call-template name="sortTokens">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="tokens" select="substring-after($lessThan,$separator)"/>
<xsl:with-param name="trailWith" select="$separator"/>
</xsl:call-template>
<xsl:value-of select="$pivot"/>
<xsl:call-template name="sortTokens">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="tokens" select="substring-after($moreThan,$separator)"/>
<xsl:with-param name="leadWith" select="$separator"/>
</xsl:call-template>
</xsl:when>
<!-- If the first token is less than the pivot, put it in the lessThan bucket -->
<xsl:when test="number($pivotVsFirstToken) = 1">
<xsl:call-template name="sortTokens">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="tokens" select="substring-after($tokens,$separator)"/>
<xsl:with-param name="pivot" select="$pivot"/>
<xsl:with-param name="lessThan" select="concat($separator,$firstToken,$lessThan)"/>
<xsl:with-param name="moreThan" select="$moreThan"/>
</xsl:call-template>
</xsl:when>
<!-- If the first token is more than the pivot, put it in the moreThan bucket -->
<xsl:otherwise>
<xsl:call-template name="sortTokens">
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="tokens" select="substring-after($tokens,$separator)"/>
<xsl:with-param name="pivot" select="$pivot"/>
<xsl:with-param name="lessThan" select="$lessThan"/>
<xsl:with-param name="moreThan" select="concat($separator,$firstToken,$moreThan)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Quote an apostrophe -->
<xsl:variable name="apos" select=""'""/>
<!-- The comparison order of the characters -->
<xsl:variable name="characterOrder" select="concat(' !"#$%&',$apos,'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~')"/>
<!-- Return -1 if string a is less, 1 if string b is less, or 0 if they are equal -->
<xsl:template name="compareStrings">
<xsl:param name="a" select="''"/>
<xsl:param name="b" select="''"/>
<xsl:choose>
<xsl:when test="$a = '' and $b = ''">0</xsl:when>
<xsl:when test="$a = ''">-1</xsl:when>
<xsl:when test="$b = ''">1</xsl:when>
<xsl:when test="substring($a,1,1) = substring($b,1,1)">
<xsl:call-template name="compareStrings">
<xsl:with-param name="a" select="substring($a,2)"/>
<xsl:with-param name="b" select="substring($b,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains(substring-after($characterOrder,substring($a,1,1)),substring($b,1,1))">-1</xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:template>
If your processor supports EXSLT, you'd better use str:tokenize
For sorting, why not use xsl:sort?
<xsl:template match="/">
<xsl:variable name="tokens">
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="'strawberry blueberry orange raspberry lime lemon'" />
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="$tokens">
<xsl:sort select="text()" />
<xsl:value-of select="." />
<xsl:if test="not(last())">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
Note that you might need exsl:node-set do to the iteration.