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>
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.
in a version="2.0" stylesheet:
the following code produces the correct output
<xsl:variable name="obj">
<xsl:choose>
<xsl:when test="t:ReferencedObjectType='Asset'">
<xsl:value-of select="/t:Flow/t:FHeader/t:Producer/t:Repository" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:value-of select="$obj"/>
but this one does not
<xsl:variable name="obj">
<xsl:choose>
<xsl:when test="t:ReferencedObjectType='Asset'">
<xsl:value-of select="/t:Flow/t:FHeader/t:Producer" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:value-of select="$obj/t:Repository"/>
How can I get the second code to run as expected ?
If needed, is there a solution in v3 ?
this code does not run either
<xsl:variable name="obj">
<xsl:choose>
<xsl:when test="t:ReferencedObjectType='Asset'">
<xsl:copy-of select="/t:Flow/t:FHeader/t:Producer" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:value-of select="$obj/t:Repository"/>
relevant xml input
<Flow>
<FHeader>
<Producer>
<Repository>tests.com</Repository>
</Producer>
</FHeader>
</Flow>
You can simply select <xsl:variable name="obj" select="/t:Flow/t:FHeader/t:Producer/t:Repository[current()/t:ReferencedObjectType='Asset']"/>. Or, as Tim already commented, use xsl:copy-of, also taking into account that you then later on need e.g. $obj/t:Producer/t:Repository to select the right level.
Or learn about the as attribute and use e.g. <xsl:variable name="obj" as="element()*">...<xsl:copy-of select="/t:Flow/t:FHeader/t:Producer"/> ...</xsl:variable>, then you later on can use e.g. $obj/t:Repository.
There is also xsl:sequence to select input nodes instead of copying them, in particular with xsl:variable if you use the as attribute. This might consume less memory.
Furthermore XPath 2 and later have if (condition-expression) then expression else expression conditional expressions at the expression level so you might not need XSLT with xsl:choose/xsl:when but could use the <xsl:variable name="obj" select="if (t:ReferencedObjectType='Asset']) then /t:Flow/t:FHeader/t:Producer else if (...) then ... else ()"/>, that way you would select e.g. an input t:Producer element anyway and if you use the variable you can directly select the t:Repository child.
I have been researching and haven't been able to find anything related to optimizing XSLT. Below is the snippet that I am working on and wanted to see if anything can be done to help with the xslt transformation.
<xsl:template match="a:OBR/*">
<xsl:choose>
<xsl:when test ="name() = 'OBR-10' and string-length(.) = 0">
<OBR-10>USER</OBR-10>
</xsl:when>
<xsl:when test ="name() = 'OBR-18'">
<OBR-18>
<xsl:value-of select ="//a:PV1/a:PV1-44"/>
</OBR-18>
</xsl:when>
<xsl:when test ="name() = 'OBR-19'">
<OBR-19>
<xsl:if test = "string-length(str:tokenize(../a:OBR-18,'^')[5]) > 0">
<xsl:value-of select ="str:tokenize(../a:OBR-18,'^')[5]"/>
</xsl:if>
</OBR-19>
</xsl:when>
<xsl:when test ="name() = 'OBR-33'">
<OBR-33>
<xsl:value-of select ="translate(../parent::a:ORC[1]/a:ORC-4,'^','~')"/>
</OBR-33>
</xsl:when>
<xsl:when test="name()='NTE'">
<NTE>
<xsl:apply-templates/>
</NTE>
</xsl:when>
<xsl:when test="name()='DG1'"/>
<!--<DG1>
<xsl:apply-templates/>
</DG1>
</xsl:when>-->
<xsl:when test="name()='OBX'">
<OBX>
<xsl:apply-templates/>
</OBX>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I would suggest to write code like
<xsl:template match="a:OBR/*">
<xsl:choose>
<xsl:when test ="name() = 'OBR-10' and string-length(.) = 0">
<OBR-10>USER</OBR-10>
</xsl:when>
as
<xsl:template match="a:OBR/OBR-10[string-length() = 0]">
<xsl:copy>USER</xsl:copy>
</xsl:template>
or perhaps
<xsl:template match="a:OBR/OBR-10[. = '']">
<xsl:copy>USER</xsl:copy>
</xsl:template>
that is, to write templates that match each element by its name and if needed a predicate/condition instead of that odd approach to match on * and then test the name. I don't see that necessarily as an optimization (you would have to measure with a particular implementation) but as a clear and modular coding style.
The
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
would then be code as
<xsl:template match="a:OBR/*">
<xsl:copy-of select="."/>
</xsl:template>
or probably already covered by an identity transformation template set up as the starting point to initiate and keep up the processing.
You would have to show the namespaces in the input document and the XSLT to allow a precise suggestion in terms of namespaces (could be that you want/need xsl:template match="a:OBR/a:OBR-10[string-length() = 0]").
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 have two variables named editable and display.
If the value of editable is true, I want to set the value of display to 'block'.
If the value of editable is false, I want to set the value of display to 'none'.
This is what I have currently:
<xsl:param name="editable" select="true()"/>
<xsl:choose>
<xsl:when test="$editable">
<xsl:variable name="display" select="'block'"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="display" select="'none'"/>
</xsl:otherwise>
</xsl:choose>
The code above doesn't set the value of display to none.
How do we change the value of a variable based on another variable?
I did not test this, but for me it looks like a problem of scope which might be solved this way:
<xsl:param name="editable" select="true()"/>
<xsl:variable name="display">
<xsl:choose>
<xsl:when test="$editable">
<xsl:value-of select="'block'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'none'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>