The function normalize-space
replaces sequences of whitespaces by a single space and trims the provided string. How can I only trim the string without the replacement of whitespaces? There are proprietary solutions like orcl:left-trim
, but I am looking for a non-proprietary one.
Example:
<xsl:value-of select="trim(/Car/Description)"/>
should turn
<car>
<description> To get more information look at: www.example.com </description>
</car>
into
"To get more information look at: www.example.com"
A solution using just xslt 1.0 templates:
<xsl:variable name="whitespace" select="'	 '" />
<!-- Strips trailing whitespace characters from 'string' -->
<xsl:template name="string-rtrim">
<xsl:param name="string" />
<xsl:param name="trim" select="$whitespace" />
<xsl:variable name="length" select="string-length($string)" />
<xsl:if test="$length > 0">
<xsl:choose>
<xsl:when test="contains($trim, substring($string, $length, 1))">
<xsl:call-template name="string-rtrim">
<xsl:with-param name="string" select="substring($string, 1, $length - 1)" />
<xsl:with-param name="trim" select="$trim" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<!-- Strips leading whitespace characters from 'string' -->
<xsl:template name="string-ltrim">
<xsl:param name="string" />
<xsl:param name="trim" select="$whitespace" />
<xsl:if test="string-length($string) > 0">
<xsl:choose>
<xsl:when test="contains($trim, substring($string, 1, 1))">
<xsl:call-template name="string-ltrim">
<xsl:with-param name="string" select="substring($string, 2)" />
<xsl:with-param name="trim" select="$trim" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<!-- Strips leading and trailing whitespace characters from 'string' -->
<xsl:template name="string-trim">
<xsl:param name="string" />
<xsl:param name="trim" select="$whitespace" />
<xsl:call-template name="string-rtrim">
<xsl:with-param name="string">
<xsl:call-template name="string-ltrim">
<xsl:with-param name="string" select="$string" />
<xsl:with-param name="trim" select="$trim" />
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="trim" select="$trim" />
</xsl:call-template>
</xsl:template>
Test code:
<ltrim>
<xsl:call-template name="string-ltrim">
<xsl:with-param name="string" select="' test '" />
</xsl:call-template>
</ltrim>
<rtrim>
<xsl:call-template name="string-rtrim">
<xsl:with-param name="string" select="' test '" />
</xsl:call-template>
</rtrim>
<trim>
<xsl:call-template name="string-trim">
<xsl:with-param name="string" select="' test '" />
</xsl:call-template>
</trim>
Output:
<test>
<ltrim>test </ltrim>
<rtrim>
test</rtrim>
<trim>test</trim>
</test>
A very short solution with XSLT1:
<xsl:template name="trim">
<xsl:param name="str"/>
<xsl:choose>
<xsl:when test="string-length($str) > 0 and substring($str, 1, 1) = ' '">
<xsl:call-template name="trim"><xsl:with-param name="str"><xsl:value-of select="substring($str, 2)"/></xsl:with-param></xsl:call-template></xsl:when>
<xsl:when test="string-length($str) > 0 and substring($str, string-length($str)) = ' '">
<xsl:call-template name="trim"><xsl:with-param name="str"><xsl:value-of select="substring($str, 1, string-length($str)-1)"/></xsl:with-param></xsl:call-template></xsl:when>
<xsl:otherwise><xsl:value-of select="$str"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
normalize-space(actualSting) - This will do it.
Using FXSL (open source library for XSLT functional programming, written entirely in XSLT) one simply writes:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="trim.xsl"/>
<xsl:output method="text"/>
<xsl:template match="/*/description">
'<xsl:call-template name="trim">
<xsl:with-param name="pStr" select="."/>
</xsl:call-template>'
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<car>
<description> To get more information look at: www.example.com </description>
</car>
the wanted, correct result is produced:
'To get more information look at: www.example.com'
How does the trim
template work?
It trims the left leading whitespace, then it reverses the resulting string and trims its leading whitespace, then it finally reverses the resulting string.
II. XPath 2.0 solution:
Use:
replace(replace(/*/description, '^\s*(.+?)\s*$', '$1'), '^ .*$', '')
Here is an XSLT - 2.0 - based verification:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
"<xsl:sequence
select="replace(replace(/*/description, '^\s*(.+?)\s*$', '$1'), '^ .*$', '')"/>"
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document (above), the XPath expression is evaluated and the result of this evaluation is copied to the output:
"To get more information look at: www.example.com"
If you don't have any spaces in the middle, you can simply use:
translate(/Car/Description,' ','')