I'm completely new to XSL and I have a query on how to convert a number into decimal format when we have text in the XML node.
For example:
<Salary> 15000 USD </Salary>
Expected out:
15,000 USD
I've used the below transformation (which I found here), however it only converts when there is no text:
<xsl:choose>
<xsl:when test="$Salary >= 1000">
<xsl:value-of select="format-number(floor($Salary div 1000), '#,##')" />
<xsl:text>,</xsl:text>
<xsl:value-of select="format-number($Salary mod 1000, '000')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($Salary, '#,###')" />
</xsl:otherwise>
</xsl:choose>
Any help would be really appreciated.
First thing, you need to convert the input to a number by removing all non-digit characters.
Assuming you are using XSLT 1.0, that would be done as:
<xsl:variable name="salary" select="translate(Salary, translate(Salary, '0123456789', ''), '')"/>
Here we assume the input will be always a positive integer - hence no minus sign or decimal point.
Once you have that, you can proceed to format the resulting number as:
<xsl:choose>
<xsl:when test="$salary >= 1000">
<xsl:value-of select="format-number(floor($salary div 1000), '#,##')" />
<xsl:text>,</xsl:text>
<xsl:value-of select="format-number($salary mod 1000, '000')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($salary, '#,###')" />
</xsl:otherwise>
</xsl:choose>
<xsl:text> USD</xsl:text>
Note:
It looks like you want to format the number as Indian currency - which seems very strange, given that the amount is in USD.
Related
Have the below newbie question on how to compare and find the greater of 2 strings please -
<xsl:variable name="String1" select="ABC"/>
<xsl:variable name="String2" select="DEF"/>
My focus of comparison between the 2 strings is based on the first letter being greater than the other, so, i did this -
<xsl:variable name="String1First" select="substring($String1,1,1)"/>
<xsl:variable name="String2First" select="substring($String2,1,1)"/>
so i have the values of the first letters in string1First & String2First for the compare.
Now the actual comparison is the issue - just tried to check if string1 > string2 but that didnt give me the right result obviously.
<xsl:variable name="Output">
<xsl:choose>
<xsl:when test="'$String1First' > '$String2First'">
<xsl:text> First string is greater </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> Second string is greater </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
tried using compare function, but that didn't seem to work.
<xsl:variable name="Output">
<xsl:choose>
<xsl:when test="(compare('$String1First', '$String2First')) = 1">
<xsl:text> First string is greater </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> Second string is greater </xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
also tried:
<xsl:variable name="Alphabet" select="ABCDEFGHIJKLMNOPQRSTUVWXYZ"/>
<xsl:number name="PosNo" select="index-of-string($Alphabet,$String1First)">
<xsl:number name="PosNo2" select="index-of-string($Alphabet,$String2First)">
to compare as numbers by taking the position, but got the whole format wrong.
Could you please help with the easiest way to achieve this please?
Many thanks for your kind assistance.
I'm new to XSLT. I'm working with zip codes and I'm trying to padleft zeros to any zipcode under 5 characters. Otherwise, I want my code to simply write the input parameter exactly as is. I'm running into a problem when the zipcode starts with or contains a letter. My output is returning a NaN. How do I tell the code that whenever the zipcode contains a letter, to simply write out the zipcode as is without running the "format-number" logic? I know about the "starts-with" and "contain" functions but I don't totally understand how they work.
<xsl:template name="MyZipCodeUnder5DigitsPadLeftZerosTemplate">
<xsl:param name="BillToZipcode" />
<xsl:choose>
<xsl:when test="string-length($BillToZipcode) < 5">
<xsl:element name="PostalCode">
<xsl:value-of select="format-number($BillToZipcode, '00000')" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="PostalCode">
<xsl:value-of select="$BillToZipcode"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
How about:
<xsl:template name="MyZipCodeUnder5DigitsPadLeftZerosTemplate">
<xsl:param name="BillToZipcode" />
<PostalCode>
<xsl:choose>
<xsl:when test="number($BillToZipcode)">
<xsl:value-of select="format-number($BillToZipcode, '00000')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$BillToZipcode"/>
</xsl:otherwise>
</xsl:choose>
</PostalCode>
</xsl:template>
This assumes no (numerical) Zipcode can have more than 5 digits. If this is not true, you could use:
<xsl:when test="number($BillToZipcode) < 10000">
i am trying to do equal comparison of negative number, but i dont see any output. below is the code.
<xsl:variable name="OwnershipStatus" select="Veh_Ownsp[Veh_Ownsp_ID=$OwnerData1/Veh_Ownsp_ID]/Ownsp_Cntl_Type_ID"/>
Here OwnershipStatus is returninenter code hereg -1
xsl:choose>
<xsl:when test="$OwnershipStatus = -1" >
<xsl:value-of select="Or"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="And"/>
</xsl:otherwise>
</xsl:choose>
I guess you are trying to hardcode 'Or' and 'And' in case of condition getting evaluated to true and false, respectively. Since the values are literal they should be enclosed with single quotes as shown below:
<xsl:choose>
<xsl:when test="$OwnershipStatus = -1" >
<xsl:value-of select="'Or'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'And'"/>
</xsl:otherwise>
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 :-))
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,'-')"/>