unceasing
asked on
sort a tokenized string in xsl
I need to sort a string such as "strawberry|blueberry|oran ge|raspber ry|lime|le mon" which appears in an xsl attribute
If you need to do this in XSLT1, you will have some issues
- XSLT only sorts on iterating a nodeset, so first you need to make some XML nodeset from the string in a first step and then use some node-set functionality
but node-set() are extension functions bound to particular processors (for processors that support it)... so I need to know which processor you use then
- or build an extension function that does that for you (means step out teh XSLT one way or another and do the sort in JavaScript or C# or whatever)
also this is processor dependent
- XSLT only sorts on iterating a nodeset, so first you need to make some XML nodeset from the string in a first step and then use some node-set functionality
but node-set() are extension functions bound to particular processors (for processors that support it)... so I need to know which processor you use then
- or build an extension function that does that for you (means step out teh XSLT one way or another and do the sort in JavaScript or C# or whatever)
also this is processor dependent
ASKER
Using the stylesheet such as below,
for a string such as strawberry|orange|grapes
I get the result of the <xsl:copy-of .. statement for the variable as
<?xml version="1.0" encoding="UTF-16"?><tokens ><token>st rawberry</ token> <token>orange</token> <token>grapes</token> </tokens>
but I'm not able to sort it alphabetically. When trying to implement any kind of sorting I get the error - "The expression does not evaluate to node-set"
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates select="//Page"></xsl:appl y-template s>
</xsl:template>
<xsl:template match="//Page">
<xsl:variable name="tokens">
<tokens>
<xsl:call-template name="tokenize">
<xsl:with-param name="string">
<xsl:value-of select="//Page/@Keywords"/ >
</xsl:with-param>
<xsl:with-param name="delimiter">|</xsl:wi th-param>
</xsl:call-template>
</tokens>
</xsl:variable>
<xsl:copy-of select="$tokens"/>
</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($s tring, $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>
for a string such as strawberry|orange|grapes
I get the result of the <xsl:copy-of .. statement for the variable as
<?xml version="1.0" encoding="UTF-16"?><tokens
but I'm not able to sort it alphabetically. When trying to implement any kind of sorting I get the error - "The expression does not evaluate to node-set"
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates select="//Page"></xsl:appl
</xsl:template>
<xsl:template match="//Page">
<xsl:variable name="tokens">
<tokens>
<xsl:call-template name="tokenize">
<xsl:with-param name="string">
<xsl:value-of select="//Page/@Keywords"/
</xsl:with-param>
<xsl:with-param name="delimiter">|</xsl:wi
</xsl:call-template>
</tokens>
</xsl:variable>
<xsl:copy-of select="$tokens"/>
</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($
</token>
<xsl:text> </xsl:text>
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="substring-after($s
<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>
ASKER
I'm using MSXML4.0 as the processor.
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Works like a charm. Thank you.
welcome
ASKER
Hi Gertone,
I would like to ask a followup question on this.
Now i have all my keywords in the sorted order. Now for each of these tokens I would like to go back to the page element and get the element's title if the title occurs in the element. Could you please suggest how to write code for this.
<xsl:for-each select="msxsl:node-set($ke ywords)//k eyword">
<xsl:sort select="." data-type="text" order="ascending"/>
<xsl:if test="not(position() = 1)">
<xsl:text><br></xsl: text>
</xsl:if>
<xsl:variable name="currentindex">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:call-template name="findindex">
<xsl:with-param name="currentindex">
<xsl:value-of select="$currentindex"/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="findindex">
<xsl:param name="currentindex"></xsl: param>
<div><xsl:value-of select="$currentindex"/></ div>
.......
</xsl:template>
I would like to ask a followup question on this.
Now i have all my keywords in the sorted order. Now for each of these tokens I would like to go back to the page element and get the element's title if the title occurs in the element. Could you please suggest how to write code for this.
<xsl:for-each select="msxsl:node-set($ke
<xsl:sort select="." data-type="text" order="ascending"/>
<xsl:if test="not(position() = 1)">
<xsl:text><br></xsl:
</xsl:if>
<xsl:variable name="currentindex">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:call-template name="findindex">
<xsl:with-param name="currentindex">
<xsl:value-of select="$currentindex"/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="findindex">
<xsl:param name="currentindex"></xsl:
<div><xsl:value-of select="$currentindex"/></
.......
</xsl:template>
<xsl:for-each select="tokenize(., '\|')">
<xsl:sort select="." data-type="text" order="ascending"/>
<xsl:if test="not(position() = 1)">
<xsl:text>|</xsl:text>
</xsl:if>
<xsl:value-of select="."></xsl:value-of>
</xsl:for-each>