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.
Related
I am having an issue that I cannot figure out in XLST where there are hardcoded 0's being added to the end of a string that I am not calling for. I am using a choose element to prompt placement of the string or to otherwise pick three 0's.
Can anyone tell in my code what I am doing wrong? See below:
<xsl:for-each select="Export/Record">
<xsl:if test="DebitAmount!=0 and DebitAmount!=''">
<xsl:value-of select="ChargedCorpLedgerCode" /><xsl:text>,</xsl:text>
<xsl:value-of select="DepartmentLedgerCode" /><xsl:text>,</xsl:text>
<xsl:value-of select="CategoryJournalNumber" /><xsl:text>,</xsl:text>
<xsl:value-of select="PFAM" /><xsl:text> 0000,</xsl:text>
<xsl:value-of select="LOC" /><xsl:text> 0000,</xsl:text>
<xsl:value-of select="ACTV" /><xsl:text> 0000,</xsl:text>
<xsl:value-of select="CLIENT"/><xsl:text> 0000000,</xsl:text>
<xsl:choose>
<xsl:when test="ProjectLedgerCode=null">
<xsl:value-of select="ProjectLedgerCode" /><xsl:text>,</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="ProjectLedgerCode" /><xsl:text> 000,</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="DebitAmount" /><xsl:text>,</xsl:text>
<xsl:value-of select="''" /><xsl:text>,</xsl:text>
<xsl:value-of select="CategoryDesc" /><xsl:text>,</xsl:text>
<xsl:text>
</xsl:text>
</xsl:if>
my outcome looks like the below where the 000's are adding correctly when the column is blank, but when it is not, it adds the ProjectLedgerCode + 000
This test:
<xsl:when test="ProjectLedgerCode=null">
will return true if the string-value of ProjectLedgerCode is equal to the string-value of a sibling element named null.
If you want to test for ProjectLedgerCode not having a string-value, use:
<xsl:when test="ProjectLedgerCode=''">
or:
<xsl:when test="not(string(ProjectLedgerCode))">
In addition, I believe your results are mixed up.
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'm trying to built some rules around a calculated variable value, but am struggling to get the rules to work with an output of false being returned if either or both criteria are used. I need to use both qualifying criteria, but in the process of bug testing tried each argument individually.
I have a variable called "calculation". However when a discount amount is applied to it, I do not want the value of the calculation to be below 301.12. This however is only the case when a discount amount has been applied. If the value of the calculation is below 301.12 without a discount then this is OK, and the lower value is acceptable.
What is happening however is the the lower value after the discount has been applied is still being returned when the process is run.
All help is greatly appreciated.
Here is my code:
<xsl:variable name="discountAmount">
<xsl:choose>
<xsl:when test="#affiliateID='12345'">50</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="feeAmount">
<xsl:choose>
<xsl:when test="#affiliateID='12345'">25</xsl:when>
<xsl:otherwise>50</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="grossAmount" select="format-number(db1:grossPremium, '#0.00')" />
<xsl:variable name="discountGiven" select="($grossAmount - $feeAmount) div 100 * $discountAmount" />
<xsl:variable name="calculation" select="($grossAmount - $discountGiven)" />
<xsl:choose>
<xsl:when test="$discountAmount > 0">
<xsl:choose>
<xsl:when test="$calculation < 301.12">
<xsl:value-of select="$calculation=301.12" />
</xsl:when>
</xsl:choose>
</xsl:when>
</xsl:choose>
You cannot change values of variables in XSLT. Try it like this:
<xsl:variable name="calc0" select="($grossAmount - $discountGiven)" />
<xsl:variable name="calculation">
<xsl:choose>
<xsl:when test="$discountAmount > 0 and $calc0 < 301.12">
301.12
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$calc0" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
I have to set a variable value in XSLT based on whether the value in an xpath is one among a list of values. Is there any way other than doing
<xsl:variable name="isBuyable">
<xsl:choose>
<xsl:when test="$someVar='A'">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:when test="$someVar='B'">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:when test="$someVar='C'">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
or like
<xsl:variable name="isBuyable">
<xsl:choose>
<xsl:when test="$someVar='A' or $someVar='B' or $someVar='C'">
<xsl:value-of select="true()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
someVar holds the value in an xpath.
Is it possible to do something like <xsl:when test="contains($listVar, $someVar)>" where listVar is a variable holding the list of required values?
In XSLT 2.0 you can have sequences of atomic values, so you can do
<xsl:variable name="isBuyable" select="$someVar = ('A', 'B', 'C')" />
In 1.0 you only have node sets, not atomic sequences, so it's a bit more fiddly. If your processor supports a node-set extension function (the msxsl one for Microsoft processors, exslt for most others) then you can do
<xsl:variable name="buyableValuesRTF">
<val>A</val>
<val>B</val>
<!-- etc -->
</xsl:variable>
<xsl:variable name="buyableValues" select="exslt:node-set($buyableValuesRTF)/val"/>
to create a node set with the valid values, which you can then compare against:
<xsl:variable name="isBuyable" select="$someVar = $buyableValues"/>
In both versions this works because an = comparison where one argument (or both) is a sequence succeeds if any of the elements on the left matches any of the ones on the right.
To do it in 1.0 without an extension function you'll have to fake the sequence using substring matching - define the list of allowed values as a string delimited by some character that is not in any of the values
<xsl:variable name="buyableValues" select="'|A|B|C|'"/>
and use the contains function to check for a substring:
<xsl:variable name="isBuyable" select="contains($buyableValues,
concat('|', $someVar, '|'))"/>
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 :-))