XSLT 1.0 String Length - 2 - xslt

I need to check the length of a field and then add . before last two
digits.
Example: the value of Amount is 0001234567, to be replaced as 00012345.67. Here string length will be 10.
But the command fails and is not able to retrieve the value from
($VARAmtLength-2) or ($VARAmtLength-1).
My code as below:
<xsl:variable name="VARAmtLength" select="string-length (ns0:Amount )"/>
<xsl:if test=" ($VARAmtLength> 0)">
<tns:Amount>
<xsl:value-of select="concat(substring(ns0:Amount, 1, ($VARAmtLength- 2)),'.', substring(ns0:Amount, ($VARAmtLength-1, 2)))"/>
</tns:Amount>
</xsl:if>
Any help?

I think your code is working fine.
Just replace this line with existing one:
<xsl:value-of select="concat(substring(ns0:Amount, 1, ($VARAmtLength - 2)),'.', substring(ns0:Amount, ($VARAmtLength - 1), 2))" />
1. There should be a space around subtraction operator '-'. Otherwise it will consider $VARAmtLength- as variable name.
2. You had misplaced round parentheses for second substring() function.

XML
<amount>0001234567</amount>
Xsl
<xsl:template match="/">
<xsl:variable name="length" select="//amount"/>
<xsl:if test="$length>0">
<amount>
<xsl:variable name="ajeet" select="concat(substring(//amount, 1, 8), '.')"/>
<xsl:variable name="kumar" select="substring(//amount, 9, 2)"/>
<xsl:value-of select="concat($ajeet, $kumar)"/>
</amount>
</xsl:if>
</xsl:template>

Related

XSL for each loop selecting position of first occurrence

In the following code snippet, I'm trying to get position of EMP_ID field from the available fields. This works fine if there's just one occurrence of EMP_ID.
But if there are more than one occurences then variable 'empid_field' will have positions of all the occurrences appended one after the other. i.e if EMP_ID is at postions 1, 8, and 11, then 'empid_field' would be '1811'.
Is there any way I get position of first occurrence only? Or Can I get comma separated positions atleast? (Code sample would be highly appreciated as I'm new to XSL programming)
<xsl:variable name="empid_field">
<xsl:for-each select="$fields">
<xsl:if test="internalName='EMP_ID'">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
The easiest solution which is in my mind is to extend this. But I think there are also solutions which look more pretty.
<xsl:variable name="empid_field">
<xsl:for-each select="$fields">
<xsl:if test="internalName='EMP_ID'">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="first_empid_field">
<xsl:value-of select="$empid_field[1]"/>
</xsl:variable>
The variable $first_empid_field will only have the first position value.
Ok got something ...
Created a comma separated string and picked the part before the delimiter.
<xsl:variable name="empid_fields" >
<xsl:for-each select="$fields">
<xsl:if test="internalName='EMP_ID'">
<xsl:value-of select="position()" />
<xsl:text >, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="empid_field" >
<xsl:value-of select="substring-before($empid_fields, ', ')" />
</xsl:variable>

Replacing specific character to lowercase using xsl

Hi i have an xml as below.
<setField identifier=”2”>
<fieldValues>
<fieldValue>
<field>event</field>
<value>
<boundVariable>$event1</boundVariable>
</value>
<type>java.lang.String</type>
</fieldValue>
</fieldValues>
<variable>append</variable>
</setField>
I need to convert to the following format.
<freeForm><text>append.setEvent($event1);</freeForm></text>
I am trying the following approach.
<xsl:template match="setField" name="setFieldTemplate">
<xsl:element name="freeForm">
<xsl:element name="text">
<xsl:value-of select="variable" />
<xsl:text>.set</xsl:text>
<xsl:value-of select="concat(translate(substring(field, 1, 1)"/>
<xsl:text>(</xsl:text>
<xsl:value-of select="boundVariable"/>
<xsl:text>);</xsl:text>
</xsl:element>
</xsl:element>
</xsl:template>
Here my requirment is based on the field name i need to generate corresponding statement as below.For that i need to change the first character of the field name to upper while generating to the following format.
append.setEvent($event1);
Here the field name is "event" and i need to generate setEvent(for which i am concatinating with the string "set").But i need to change the fieldname's first letter to upper one(Event from event).when i try with the above template with translate function i am facing some invalid xpath expression.
Please provide me some pointers to do the same.
<xsl:value-of select="concat(
variable,
'.set',
translate(substring(//field, 1, 1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
substring(//field, 2),
'(',
//boundVariable,
');'
)"/>
You want:
<xsl:value-of select="concat(
translate(substring(//field, 1, 1),
'abcdefghijklmnstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
substring(//field, 2))"/>
Also you might prefer:
<xsl:template match="setField">
<freeForm>
<text>
<xsl:value-of select="variable" />
<xsl:text>.set</xsl:text>
<xsl:value-of select="concat(
translate(
substring(fieldValues/fieldValue/field, 1, 1),
'abcdefghijklmnstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
substring(fieldValues/fieldValue/field, 2),
'(',fieldValues/fieldValue/value/boundVariable,');')"/>
</text>
</freeForm>
</xsl:template>

Custom format for <xsl:number>

Is it possible to define a custom format for <xsl:number>?
I have the case where a standard alpha-based format is desired, but certain characters in the alphabet are forbidden (strange requirement, but it is what the client requires). For example, the letter i cannot be used, so when using <xsl:number> I should get the sequence: a, b, c, d, e, f, g, h, j, k, ..., aa, ab, ..., ah, aj, ...
The project is using XSLT 2.0 and Saxon, so if a solution exists that is specific to Saxon, that is okay.
Does XSLT 2.0 provide the capability to define a custom format sequence? Does Saxon provide a capability to register a custom sequence for use with <xsl:number>?
XSLT 2.0 provides the format attribute for xsl:number by which you can use the format token aa for example. The computed number depends by the expression evaluated inside value attribute and will be formatted accordingly to format.
Given this, you can think of first evaluating the correct sequence of numbers excluding those that will match for a particular letter.
For instance, the following instruction:
<xsl:number value="$sequence" format="aa"/>
will print (notice i excluded):
a.b.c.d.e.f.g.h.j.k.l.m
if $sequence evaluates to (notice 9 skipped):
1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13
Notice that if you have 12 elements your expression should be able to skip the unwanted number (9 for i) and increase the following of one. The last element with position 12, should have corresponding number 13.
So what you need, is just the algorithm that computes the wanted sequence; which depends definitely from your input document.
References: XSLT 2.0 Rec.
You can customize the output of xsl:number in Saxon by writing an implementation of the interface net.sf.saxon.lib.Numberer: probably you will want to make this a subclass of net.sf.saxon.expr.number.Numberer_en. You'll need to study the source code and work out what needs overriding.
In Saxon PE/EE you can register the Numberer to be used for a given language in the Saxon configuration file. For Saxon HE it requires a bit more work: you have to implement the interface LocalizerFactory and register your LocalizerFactory with the Configuration.
EDIT: An alternate, more general, solution exists and is posted as a separate answer. I'm leaving this answer since it still may be of value to some.
I like #empo's thinking (I mod'ed it up), but I think it may be hard to get a working solution. A clever algorithm/equation is required to come up with the correct sequence number based on the raw sequence to avoid getting a label that does not contain the forbidden characters. At this time, such an algorithm escapes me.
One method I came up with is to create my own function, and not use <xsl:number>. In essence, we are dealing with a base 23 set, the letters a to z, but excluding the characters i, l, and o. The function I came up with only goes up to zz, but that should be sufficient for what is needed (provides labelling up to 552 items).
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ewh="http://www.earlhood.com/XSL/Transform"
exclude-result-prefixes="#all">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="letters" select="'abcdefghjkmnpqrstuvwxyz'"/>
<xsl:variable name="lbase" select="23"/>
<xsl:function name="ewh:get-alpha-label" as="xs:string">
<xsl:param name="number" as="xs:integer"/>
<xsl:variable name="quotient" select="$number idiv $lbase"/>
<xsl:variable name="remainder" select="$number mod $lbase"/>
<xsl:variable name="p1">
<xsl:choose>
<xsl:when test="($quotient gt 0) and ($remainder = 0)">
<xsl:value-of select="substring($letters,($quotient - 1),1)"/>
</xsl:when>
<xsl:when test="($quotient gt 0) and ($remainder gt 0)">
<xsl:value-of select="substring($letters,$quotient,1)"/>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:variable>
<xsl:variable name="p0">
<xsl:choose>
<xsl:when test="$remainder = 0">
<xsl:value-of select="substring($letters,$lbase,1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($letters,$remainder,1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($p1,$p0)"/>
</xsl:function>
<xsl:template match="/">
<result>
<value n="9"><xsl:value-of select="ewh:get-alpha-label(9)"/></value>
<value n="12"><xsl:value-of select="ewh:get-alpha-label(12)"/></value>
<value n="15"><xsl:value-of select="ewh:get-alpha-label(15)"/></value>
<value n="23"><xsl:value-of select="ewh:get-alpha-label(23)"/></value>
<value n="26"><xsl:value-of select="ewh:get-alpha-label(26)"/></value>
<value n="33"><xsl:value-of select="ewh:get-alpha-label(33)"/></value>
<value n="46"><xsl:value-of select="ewh:get-alpha-label(46)"/></value>
<value n="69"><xsl:value-of select="ewh:get-alpha-label(69)"/></value>
<value n="70"><xsl:value-of select="ewh:get-alpha-label(70)"/></value>
<value n="200"><xsl:value-of select="ewh:get-alpha-label(200)"/></value>
<value n="552"><xsl:value-of select="ewh:get-alpha-label(552)"/></value>
</result>
</xsl:template>
</xsl:stylesheet>
When I execute the above, I get the following output:
<result>
<value n="9">j</value>
<value n="12">n</value>
<value n="15">r</value>
<value n="23">z</value>
<value n="26">ac</value>
<value n="33">ak</value>
<value n="46">az</value>
<value n="69">bz</value>
<value n="70">ca</value>
<value n="200">hs</value>
<value n="552">zz</value>
</result>
It would be nice of XSLT provided the capability to define a custom character sequence for use with <xsl:number>. Seems like such a capability would generalize <xsl:number> w/o relying on custom extensions, which I do not know if any XSLT engine provides for <xsl:number>.
I came up with the following, more generalized solution, after posting my original solution to the problem. The solution is pure XSLT and at the base, still uses <xsl:number>, so should be applicable to any format type.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ewh="http://www.earlhood.com/XSL/Transform"
exclude-result-prefixes="#all">
<!-- Description: XSLT to generate a alpha formatted sequence
label (via <xsl:number>), but disallowing specific characters
from being used.
-->
<!-- Algorithm: Given the index value of the item to generate
a label for via <xsl:number>, we adjust the value so the resulting
label avoids the use of the forbidden characters.
This is achieved by converting the index value into a baseX
number, with X the number of allowed characters.
The baseX number will be converted into a reverse sequence
of numbers for each ^E place. For example, the number 12167
converted to base23 will generate the following reverse sequence:
Place: (23^0, 23^1, 23^2, 23^3)
Sequence: ( 0, 0, 0, 1) // 1000 in base23
Having it in right-to-left order makes processing easier.
Each item in the sequence will be a number from 0 to baseX-1.
With the sequence, we can then just call <xsl:number> on
each item and reverse concatenate the result.
NOTE: Since <xsl:number> does not like 0 as a given value,
the sequence must be processed so each item is within the
range of 1-to-baseX. For example, the above base23 example
will be translated to the following:
(23, 22, 22)
-->
<xsl:output method="xml" indent="yes"/>
<!-- Number of allowed characters: This should be total number of chars of
format-type desired minus the chars that should be skipped. -->
<xsl:variable name="lbase" select="23"/>
<!-- Sequence of character positions not allowed, with 1=>a to 26=>z -->
<xsl:variable name="lexcs" select="(9,12,15)"/> <!-- i,l,o -->
<!-- Helper Function:
Convert integer to sequence of number of given base.
The sequence of numbers is in reverse order: ^0,^1,^2,...^N.
-->
<xsl:function name="ewh:get_base_digits" as="item()*">
<xsl:param name="number" as="xs:integer"/>
<xsl:param name="to" as="xs:integer"/>
<xsl:variable name="Q" select="$number idiv $to"/>
<xsl:variable name="R" select="$number mod $to"/>
<xsl:sequence select="$R"/>
<xsl:if test="$Q gt 0">
<xsl:sequence select="ewh:get_base_digits($Q,$to)"/>
</xsl:if>
</xsl:function>
<!-- Helper Function:
Compute carry-overs in reverse-base digit sequence. XSLT starts
numbering at 1, so we cannot have any 0s.
-->
<xsl:function name="ewh:compute_carry_overs" as="item()*">
<xsl:param name="digits" as="item()*"/>
<xsl:variable name="d" select="subsequence($digits, 1, 1)"/>
<xsl:choose>
<xsl:when test="($d le 0) and (count($digits) = 1)">
<!-- 0 at end of list, nothing to do -->
</xsl:when>
<xsl:when test="$d le 0">
<!-- If digit <=0, need to perform carry-over operation -->
<xsl:variable name="next" select="subsequence($digits, 2, 1)"/>
<xsl:choose>
<xsl:when test="count($digits) le 2">
<xsl:sequence select="$lbase + $d"/>
<xsl:sequence select="ewh:compute_carry_overs($next - 1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$lbase + $d"/>
<xsl:sequence select="ewh:compute_carry_overs(($next - 1,
subsequence($digits, 3)))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="count($digits) le 1">
<xsl:sequence select="$d"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$d"/>
<xsl:sequence select="ewh:compute_carry_overs(subsequence($digits, 2))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- Helper Function:
Given a number in the base range, determine number for
purposes of <xsl:number>. We loop thru the exclusion
list and add 1 for each exclusion letter that has
been passed. The $digit parameter should be a number
in the range [1..$lbase].
-->
<xsl:function name="ewh:compute_digit_offset" as="xs:integer">
<xsl:param name="digit" as="xs:integer"/>
<xsl:param name="excludes" as="item()*"/>
<xsl:variable name="l" select="subsequence($excludes, 1, 1)"/>
<xsl:variable name="result">
<xsl:choose>
<xsl:when test="$digit lt $l">
<xsl:value-of select="0"/>
</xsl:when>
<xsl:when test="count($excludes) = 1">
<xsl:value-of select="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="rest">
<xsl:value-of select="ewh:compute_digit_offset($digit+1,
subsequence($excludes,2))"/>
</xsl:variable>
<xsl:value-of select="1 + $rest"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="$result"/>
</xsl:function>
<!-- Retrieve alpha sequence label.
This is the main function to call.
-->
<xsl:function name="ewh:get-alpha-label" as="xs:string">
<xsl:param name="number" as="xs:integer"/>
<xsl:variable name="basedigits"
select="ewh:get_base_digits($number,$lbase)"/>
<xsl:variable name="digits"
select="ewh:compute_carry_overs($basedigits)"/>
<xsl:variable name="result" as="item()*">
<xsl:for-each select="$digits">
<xsl:variable name="digit" select="."/>
<!-- Should not have any 0 values. If some reason we do,
we ignore assuming they are trailing items. -->
<xsl:if test="$digit != 0">
<xsl:variable name="value">
<xsl:value-of select="$digit +
ewh:compute_digit_offset($digit,$lexcs)"/>
</xsl:variable>
<xsl:variable name="number">
<xsl:number value="$value" format="a"/>
</xsl:variable>
<xsl:sequence select="$number"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="string-join(reverse($result),'')"/>
</xsl:function>
<!-- For testing -->
<xsl:template match="/">
<result>
<xsl:for-each select="(1 to 1000,12166,12167,12168,279840,279841,279842)">
<value n="{.}"><xsl:value-of select="ewh:get-alpha-label(.)"/></value>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>

Formatting scientific number representation in xsl

I have the following value in my XML -1.8959581529998104E-4. I want to format this to the exact number it should be using XSL to give me -0.000189595815299981.
format-number(-1.8959581529998104E-4,'0.000000;-0.000000') gives me NaN.
Any ideas?
Cheers
Andez
XSLT 1.0 does not have support for scientific notation.
This: number('-1.8959581529998104E-4')
Result: NaN
This: number('-0.000189595815299981')
Result: -0.000189595815299981
XSLT 2.0 has support for scientific notation
This: number('-1.8959581529998104E-4')
Result: -0.000189595815299981
EDIT: A very simple XSLT 1.0 workaround:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="number[substring-after(.,'E')]">
<xsl:variable name="vExponent" select="substring-after(.,'E')"/>
<xsl:variable name="vMantissa" select="substring-before(.,'E')"/>
<xsl:variable name="vFactor"
select="substring('100000000000000000000000000000000000000000000',
1, substring($vExponent,2) + 1)"/>
<xsl:choose>
<xsl:when test="starts-with($vExponent,'-')">
<xsl:value-of select="$vMantissa div $vFactor"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$vMantissa * $vFactor"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
With this input:
<number>-1.8959581529998104E-4</number>
Output:
-0.00018959581529998104
This is based on user357812 answer. But I made it act like a function and handle non-scientific notation
<xsl:template name="convertSciToNumString" >
<xsl:param name="inputVal" select="0"/>
<xsl:variable name="vExponent" select="substring-after($inputVal,'E')"/>
<xsl:variable name="vMantissa" select="substring-before($inputVal,'E')"/>
<xsl:variable name="vFactor"
select="substring('100000000000000000000000000000000000000000000',
1, substring($vExponent,2) + 1)"/>
<xsl:choose>
<xsl:when test="number($inputVal)=$inputVal">
<xsl:value-of select="$inputVal"/>
</xsl:when>
<xsl:when test="starts-with($vExponent,'-')">
<xsl:value-of select="format-number($vMantissa div $vFactor, '#0.#############')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($vMantissa * $vFactor, '#0.#############')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Usage:
<xsl:template match="X">
<X>
<xsl:call-template name="convertSciToNumString">
<xsl:with-param name="inputVal" select="text()"/>
</xsl:call-template>
</X>
</xsl:template>
This should handle a mix of scientific notation and decimal values.
Another possible workaround without a template:
<xsl:stylesheet version="1.0" ... xmlns:java="http://xml.apache.org/xslt/java">
...
<xsl:value-of select="format-number(java:java.lang.Double.parseDouble('1E-6'), '0.000')"/>
The logic doesn't appear to work correctly in the above answers by Moop and user357812 when determining vFactor in one particular scenario.
If vExponent is a single-digit positive number (without a preceding '+' sign), then vFactor is set to an empty string. This is because an assumption was made that the 1st character of vExponent would be a plus/minus sign and therefore the 2nd character onwards were of interest. The vMantissa variable is then multiplied by an empty string which results in the template outputting NaN.
If vExponent is a multi-digit positive number (without a preceding '+' sign), then vFactor is set to an incorrect value. Because of the aforementioned assumption, the 1st digit is ignored and the vMantissa is then multiplied by an incorrect vFactor.
Therefore, I've modified the previously posted code a little so that it can handle scientific numbers of the forms: 2E-4, 2E+4 and 2E4.
<xsl:template name="convertSciToNumString" >
<xsl:param name="inputVal" select="0"/>
<xsl:variable name="vMantissa" select="substring-before(., 'E')"/>
<xsl:variable name="vExponent" select="substring-after(., 'E')"/>
<xsl:variable name="vExponentAbs" select="translate($vExponent, '-', '')"/>
<xsl:variable name="vFactor" select="substring('100000000000000000000000000000000000000000000', 1, substring($vExponentAbs, 1) + 1)"/>
<xsl:choose>
<xsl:when test="number($inputVal)=$inputVal">
<xsl:value-of select="$inputVal"/>
</xsl:when>
<xsl:when test="starts-with($vExponent,'-')">
<xsl:value-of select="format-number($vMantissa div $vFactor, '#0.#############')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($vMantissa * $vFactor, '#0.#############')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Just tried this with xsltproc using libxslt1.1 in version 1.1.24 under Linux:
XSLT 1.1 is able to read in exponential/scientific format now even without any dedicated template, it seems to simply work :-))

Xslt abs function?

I an trying to transform some data. The data contained in my xml field "Source/End/Edgecode" looks like -000016
I want to remove the leading dash. I thought I could use abs or right, but I don't know the correct syntax.
Thanks for any help...
* FROM CLIP NAME:
<xsl:template name="frame_to_tc">
<xsl:param name="frame"/>
<xsl:variable name="hh" select="($frame div $fph)"/>
<xsl:variable name="rh" select="($frame mod $fph)"/>
<xsl:variable name="mm" select="($rh div $fpm)"/>
<xsl:variable name="rm" select="($rh mod $fpm)"/>
<xsl:variable name="ss" select="($rm div $fps)"/>
<xsl:variable name="rs" select="($rm mod $fps)"/>
<xsl:variable name="ff" select="($rs mod $fps)"/>
<xsl:value-of select="format-number(floor($hh),'00')"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="format-number(floor($mm),'00')"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="format-number(floor($ss),'00')"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="format-number(floor($ff),'00')"/>
<xsl:template name="abs">
<xsl:param name="input" select="0">
<xsl:variable name="num" select="number(input)" />
<xsl:choose>
<xsl:when test="$num >= 0">
<xsl:value-of select="$num" />
</xsl:when>
<xsl:when test="$num < 0">
<xsl:value-of select="-1 * $num" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$input" />
</xsl:otherwise>
</xsl:choose>
<xsl:template>
callable like this:
<xsl:variable name="absnum">
<xsl:call-template name="abs">
<xsl:with-param name="input" select="some/number" />
</xsl:call-template>
</xsl:variable>
You can use a simple substring.
<xsl:value-of select="substring($yourVariable, 2)"/>
<!-- In XSLT, the index starts from 1, so here you are taking a substring starting from the second character, in essence, leaving out the hyphen-->
Or even the node directly instead of the variable..
<xsl:value-of select="substring(/Your/Path/Here, 2)"/>
Since you are not specifying a specific number of characters to return, it will return the rest of the string completely. You can restrict the number of characters returned which is done by adding a comma and then specifying a second length upto which to cut) Ex: substring(/Your/Path/Here , 2, 5)
This will cut from the 2nd character upto five characters, If the string is "1234567" it will return "23456".
NOTE: This is assuming that you only want to remove the leading hyphen. If you want to remove the leading zeroes as well, a number() typecast should do the trick.
to remove the leading dash, try this XPath function:
<xsl:value-of select="substring-after($x,'-')"/>