patternMinor
Conditional assignment in XSLT?
Viewed 0 times
xsltassignmentconditional
Problem
I've written some XSLT where I want to assign values to some variables.
Depending on whether or not a condition is met, I want the variable to be populated with a computed value and I want it to have a default value otherwise.
I've written the following code that appears to work, but I think that there may be a better way.
Yes, my XSLT processor uses XSLT 2.0
Depending on whether or not a condition is met, I want the variable to be populated with a computed value and I want it to have a default value otherwise.
I've written the following code that appears to work, but I think that there may be a better way.
UNK
UNK
Yes, my XSLT processor uses XSLT 2.0
Solution
IMHO your code is fine. The "problem" with XSLT variables is that they are NOT variables but more resemble constants: once set they cannot be changed anymore. Also, their scope is restricted to anything that follows their definition until the closing tag. In particular they are NOT visible in any ancestor tag. The combination of both results in the type of constructs that you have used above.
What is most disturbing is the fact that you usually have to repeat the testing of the criterion again and again if several variables depend on the same criterion. Again there's nothing generic that you can do about this, but of course, you can always at least create another variable holding the result of the test and then use that several times.
Depending on the context of your XSLT I would suggest two alternatives which may or may not be more elegant:
a) works in XSLT 1.0 and 2.0: If you just define the variables to be used as parameters to a template-call consider writing the template-call twice once in the
b) Works only well in XSLT 2.0 (or a little awkward in XSLT with node-set extensions): move the check of the criterion and the selection of the definition values into a template and return the "set" of values to the assigned in a node-set. In a way you can regard this node-set as a record whose attributes have been set according to the criterion. See example below.
This solution is definitely not shorter than yours but it resembles more other standard programming languages. The record type approach may come in especially handy if you have a lot of templates requiring the attributes in the record.
What is most disturbing is the fact that you usually have to repeat the testing of the criterion again and again if several variables depend on the same criterion. Again there's nothing generic that you can do about this, but of course, you can always at least create another variable holding the result of the test and then use that several times.
Depending on the context of your XSLT I would suggest two alternatives which may or may not be more elegant:
a) works in XSLT 1.0 and 2.0: If you just define the variables to be used as parameters to a template-call consider writing the template-call twice once in the
when as once in the otherwise portion. This way you will end up with just one ``.b) Works only well in XSLT 2.0 (or a little awkward in XSLT with node-set extensions): move the check of the criterion and the selection of the definition values into a template and return the "set" of values to the assigned in a node-set. In a way you can regard this node-set as a record whose attributes have been set according to the criterion. See example below.
The value of PRODUCT is
and the value of AREA is
This solution is definitely not shorter than yours but it resembles more other standard programming languages. The record type approach may come in especially handy if you have a lot of templates requiring the attributes in the record.
Code Snippets
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template name="get_values">
<xsl:param name="catalog"/>
<xsl:choose>
<xsl:when test="count($catalog/lookup) > 0">
<PRODUCT VALUE="{$catalog/lookup/Product}"/>
<AREA VALUE="{$catalog/lookup/Area}"/>
</xsl:when>
<xsl:otherwise>
<PRODUCT VALUE="UNK"/>
<AREA VALUE="UNK"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="Catalog" select="."/>
<xsl:variable name="my_config">
<xsl:call-template name="get_values">
<xsl:with-param name="catalog" select="$Catalog"/>
</xsl:call-template>
</xsl:variable>
<xsl:message>
The value of PRODUCT is <xsl:value-of select="$my_config/PRODUCT/@VALUE"/>
and the value of AREA is <xsl:value-of select="$my_config/AREA/@VALUE"/>
</xsl:message>
</xsl:template>
</xsl:stylesheet>Context
StackExchange Code Review Q#33200, answer score: 4
Revisions (0)
No revisions yet.