15

I am newbie to xslt. My requirement is to transform xml file into text file as per the business specifications. I am facing an issue with one of the string formatting issue. Please help me out if you have any idea.

Here is the part of input xml data: "0001295"

Expected result to print into text file: 1295

My main issue is to remove leading Zeros. Please share if you have any logic/function.

Hari
  • 159
  • 1
  • 2
  • 6
  • I have similar problem, a string with two or more numbers (ex. `hello 002 and 021, bye`), that we can not solve with a trivial *"left trim"* function... But have a solution with XSLT1, since we can use [registered functions](https://en.wikibooks.org/wiki/XSLT#Registered_functions) (see answer below). – Peter Krauss Jul 23 '14 at 05:55

8 Answers8

28

Just use this simple expression:

number(.)

Here is a complete example:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="t">
      <xsl:value-of select="number(.)"/>
 </xsl:template>
</xsl:stylesheet>

When applied on this XML document:

<t>0001295</t>

the wanted, correct result is produced:

1295

II. Use format-number()

format-number(., '#')
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
8

There are a couple of ways you can do this. If the value is entirely numeric (for example not a CSV line or part of a product code such as ASN0012345) you can convert from a string to a number and back to a string again :

string(number($value)).

Otherwise just replace the 0's at the start :

replace( $value, '^0*', '' )

The '^' is required (standard regexp syntax) or a value of 001201 will be replaced with 121 (all zero's removed).

Hope that helps. Dave

detheridge02
  • 640
  • 1
  • 6
  • 18
  • Hi Dave, First of all thanks for your input. Basically I was interested in removing Leading zeros in alphanumeric string. So I used your second solution replace( $value, '^0*', '' ). When I use it following error is getting displayed. 'replace' is not a valid XSLT or XPath function. -->replace( $Part, '^0*', '' )<-- . Do you have any idea for the solution. For your information I am using xml Version 1.0. – Hari Jan 10 '12 at 11:17
  • 2
    Ahh right, replace is XSLT 2.0 Use translate instead and it should work fine : translate( $value, '^0*', '' ) – detheridge02 Jan 10 '12 at 11:31
  • OPS, error: `translate` function not process regular expressions (!). See @TimC anwser. With *XSLT1* the only way to use regex and other good functions (like `trim`) is to enables the use of the caller language (ex. PHP calling XSLT), see ex. [this Wikibook of PHP Programming/XSL/registerPHPFunctions](https://en.wikibooks.org/wiki/PHP_Programming/XSL/registerPHPFunctions). – Peter Krauss Jul 23 '14 at 05:48
7

Here is one way you could do it in XSLT 1.0.

First, find the first non-zero element, by removing all the zero elements currently in the value

<xsl:variable name="first" select="substring(translate(., '0', ''), 1, 1)" />

Then, you can find the substring-before this first character, and then use substring-after to get the non-zero part after this

<xsl:value-of select="substring-after(., substring-before(., $first))" />

Or, to combine the two statements into one

<xsl:value-of select="substring-after(., substring-before(., substring(translate(., '0', ''), 1, 1)))" />

So, given the following input

<a>00012095Kb</a>

Then using the following XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/a">
      <xsl:value-of select="substring-after(., substring-before(., substring(translate(., '0', ''), 1, 1)))" />
   </xsl:template>
</xsl:stylesheet>

The following will be output

12095Kb
Tim C
  • 70,053
  • 14
  • 74
  • 93
3

As a simple alternative in XSLT 2.0 that can be used with numeric or alpha-numeric input, with or without leading zeros, you might try:

replace( $value, '^0*(..*)', '$1' )

This works because ^0* is greedy and (..*) captures the rest of the input after the last leading zero. $1 refers to the captured group.

Note that an input containing only zeros will output 0.

SebastianBrandt
  • 439
  • 2
  • 10
3

XSLT 2.0 Remove leading zeros from STRING

<xsl:value-of select="replace( $value, '^0+', '')"/>
Mikro Koder
  • 1,056
  • 10
  • 13
2

You could use a recursive template that will remove the leading zeros:

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

Invoke it like this:

 <xsl:call-template name="remove-leading-zeros">
        <xsl:with-param name="text" select="/path/to/node/with/leading/zeros"/>
    </xsl:call-template>
</xsl:template>
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
1
<xsl:value-of select="number(.) * 1"/>

works for me

Henk de Marie
  • 77
  • 1
  • 6
0

All XSLT1 parser, like the popular libXML2's module for XSLT, have the registered functions facility... So, we can suppose to use it. Suppose also that the language that call XSLT, is PHP: see this wikibook about registerPHPFunctions.


The build-in PHP function ltrim can be used in

  <?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:fn="http://php.net/xsl">
   <xsl:output method="xml" encoding="utf-8" indent="yes"/>
   <xsl:template match="test">
       show <xsl:value-of select="fn:function('ltrim',string(.),'0')" />",
   </xsl:template>
  </xsl:stylesheet>

Now imagine a little bit more complex problem, to ltrim a string with more than 1 number, ex. hello 002 and 021, bye.

The solution is the same: use registerPHPFunctions, except to change the build-in function to a user defined one,

function ltrim0_Multi($s) {
    return preg_replace('/(^0+|(?<= )0+)(?=[1-9])/','',$s);
} 

converts the example into hello 2 and 21, bye.

Peter Krauss
  • 13,174
  • 24
  • 167
  • 304
  • Thanks @JaarSingleton. Yes, use of *registerPHPFunctions* only for solve complex problems... The main problem is the standard XSLT **v1** that was abandoned (there are no intermediary 1.1, 1.2 with grouping functionalities) and the [no-free DOM parser of XSLT v2](http://programmers.stackexchange.com/q/205580/84349). – Peter Krauss May 23 '16 at 12:31