Reputation: 3
I have a string of single values and ranges, and I want to split them and put them in order of single values together (comma separated) and ranges together (comma separated), using XSLT1.0. I don't want the result in form of XML nodes, I do want the result on the same line. I have found that existing solutions here on Stack Exchange works, but it puts them on different lines as XML nodes.
The string is:
Input: <mark>9, 11, 345-900, 100-200, 1023, 200-400, 99</mark>
Desired Output: 9, 11, 1023, 99, 345-900, 100-200, 200-400
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="mark">
<xsl:call-template name="tokenizeStringWithoutHyphen">
<xsl:with-param name="list" select="."/>
<xsl:with-param name="delimiter" select="','"/>
</xsl:call-template>
<xsl:call-template name="tokenizeStringWithHyphen">
<xsl:with-param name="list" select="."/>
<xsl:with-param name="delimiter" select="','"/>
</xsl:call-template>
</xsl:template>
<!--############################################################-->
<!--## Template to tokenize strings ##-->
<!--############################################################-->
<xsl:template name="separatestrings">
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
</xsl:template>
<xsl:template name="tokenizeStringWithHyphen">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:variable name="stringContainsHyphen" select="contains(substring-before($list,$delimiter),'-')"/>
<!--<test><xsl:value-of select="$stringContainsHyphen"/></test>-->
<xsl:choose>
<xsl:when test="$stringContainsHyphen = true()">
<!-- get everything in front of the first delimiter -->
<xsl:value-of select="normalize-space(substring-before($list,$delimiter))"/>
</xsl:when>
</xsl:choose>
<xsl:call-template name="tokenizeStringWithHyphen">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$list = ''">
<xsl:text/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$list"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="tokenizeStringWithoutHyphen">
<!--passed template parameter -->
<xsl:param name="list"/>
<xsl:param name="delimiter"/>
<xsl:choose>
<xsl:when test="contains($list, $delimiter)">
<xsl:variable name="stringContainsHyphen" select="contains(substring-before($list,$delimiter),'-')"/>
<!--<test><xsl:value-of select="$stringContainsHyphen"/></test>-->
<xsl:choose>
<xsl:when test="$stringContainsHyphen = false()">
<!-- get everything in front of the first delimiter -->
<xsl:value-of select="normalize-space(substring-before($list,$delimiter))"/>
</xsl:when>
</xsl:choose>
<xsl:call-template name="tokenizeStringWithoutHyphen">
<!-- store anything left in another variable -->
<xsl:with-param name="list" select="substring-after($list,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 1137
Reputation: 116992
I don't want the result in form of XML nodes, I do want the result on the same line.
If you want to sort the values, you must tokenize them into nodes first. Then sort the nodes and output them back as text values in a single line:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="mark">
<xsl:variable name="tokens">
<xsl:call-template name="tokenize"/>
</xsl:variable>
<xsl:for-each select="exsl:node-set($tokens)/token">
<xsl:sort select="number(contains(., '-'))" data-type="number" order="ascending"/>
<xsl:value-of select="." />
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="text" select="."/>
<xsl:param name="delimiter" select="', '"/>
<xsl:choose>
<xsl:when test="contains($text, $delimiter)">
<token>
<xsl:value-of select="substring-before($text, $delimiter)"/>
</token>
<!-- recursive call -->
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<token>
<xsl:value-of select="$text"/>
</token>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1