Monday, January 20, 2014

How to remove trailing zeros when XSLT can't do it

We ran into a situation where we needed to search the document number in a database. To avoid misleads by leading zeros, we've always converted that string to numeric using number().
number($value)


But suddenly, a huge number appeared... and XSLT was representing it in scientific notation.

What other ways can leading zeros desappear? In XSLT 2.0 we can say "remove all zeros at beginning"
replace( $value, '^0*', '' )


In XSLT 1.0 it takes more. We needed a recursive template to take down 0's one by one.

<xsl:template name="remove-leading-zeros">
<xsl:template name="remove-leading-zeros">
</xsl:template></xsl:template>
<xsl:template name="remove-leading-zeros">
<xsl:param name="value"></xsl:param>
</xsl:template><xsl:template name="remove-leading-zeros">
</xsl:template>
<xsl:template name="remove-leading-zeros">
<xsl:choose>
    <xsl:when test="starts-with($value,'0')">
      <xsl:call-template name="remove-leading-zeros">
        <xsl:with-param name="value">select="substring-after($value,'0')"/></xsl:with-param></xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$value">
</xsl:value-of>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="remove-leading-zeros">
</xsl:template>

<xsl:param name="value"><xsl:choose><xsl:when test="starts-with($value,'0')"><xsl:call-template name="remove-leading-zeros"><xsl:with-param br="" name="value"> </xsl:with-param></xsl:call-template> </xsl:when></xsl:choose></xsl:param><xsl:otherwise><xsl:value-of select="$value"></xsl:value-of></xsl:otherwise>
There is a smaller solution. It's not that easy to understand, but it works.Instead of replace we could use
translate($value, '0', '')
, but this would simply remove the 0's everywhere. Good, but not what we planned.

Use it like this to find the first non 0.
substring(translate($value, '0', ''), 1, 1)


We can't do a substring-after or we'd lose that first non-zero, but we can see what is before it.
substring-before($value, substring(translate($value, '0', ''), 1, 1))


Then, get what is after the leading 0's.
substring-after($var, substring-before($value, substring(translate($value, '0', ''), 1, 1)))


Not that bad.