<xsl:choose>
<xsl:when test="long convoluted expression">
<xsl:element name="Class">123</xsl:element>
<a lot more xsl:elements>
</xsl:when>
<xsl:when test="next very long expression">
<xml:element name="Class">124</xsl:element>
<a lot more xsl:e开发者_C百科lements>
</xsl:when>
<tens of more similar xsl:when>
</xsl:choose>
Is there a way to simplify the above code with conditionals? For every class value the objects are given, there follows tens of rows with extra attributes. These attributes form sets according to the value of the class. Class 0-99 has one set of extra tags, class 100-199 a second, forming a maintenance nightmare when one of these extra tag sets change.
I was considering a solution like this:
<xsl:choose>
<xsl:when test="long convoluted expression">
<xml:element name="Class">123</xsl:element>
<xsl:variable name="outputclass" select="123">
</xml:when>
<xsl:when test="next very long expression">
<xml:element name="Class">124</xsl:element>
<xsl:variable name="outputclass" select="124">
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="$outputclass > 99">
<xml:elements for classes 100-199 here>
</xsl:when>
<xsl:choose>
But of course this fails, as the outputclass variable is not in the same scope. Any way to go around this?
The best solution to this problem is well-known:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="voutType">
<xsl:choose>
<xsl:when test="long convoluted expression">123</xsl:when>
<xsl:when test="next very long expression">124</xsl:when>
<!-- Etcetera ... -->
</xsl:choose>
</xsl:variable>
<Class><xsl:value-of select="$voutType"</Class>
<xsl:choose>
<xsl:when test="not($voutType > 99)">
<!-- elements for classes 0 - 99 here -->
</xsl:when>
<xsl:otherwise>
<!-- elements for classes 100-199 here -->
</xsl:otherwise>
<xsl:choose>
</xsl:template>
</xsl:stylesheet>
Do note:
In order to give values to a variable (
$voutType
), the<xsl:choose>
instruction must be inside the body of the<xsl:variable>
You only need to specify the
<Class>
element once -- outside of everything else.You don't have to use
<xsl:element>
if the element name is known.
If you're trying to make it easy to specify a bunch of attributes (not tags aka elements!), then it sounds to me like attribute sets are what you need, and you may not need variables:
http://www.w3.org/TR/xslt#attribute-sets
That assumes that the attribute values themselves aren't dependent on the class's value; only their presence is.
If elements are really what you mean, try using named templates with an input parameter. At the top level of your stylesheet:
<xsl:template name="classdef">
<xsl:param name="classid"/>
<!-- Note: I put the class elem in here so I don't have to
write individual class ids more than once -->
<xsl:element name="Class"><xsl:value-of select="$classid"/></xsl:element>
<xsl:choose>
<xsl:when test="$classid > 99">
...
</xsl:when>
</xsl:choose>
</xsl:template>
and in your other template:
<xsl:call-template name="classdef">
<xsl:with-param name="classid">124</xsl:with-param>
</xsl:call-template>
See http://www.w3.org/TR/xslt#variables for more info on params.
I've only done XSLT a few times, but each time it seems like a huge maintenance nightmare. At any rate, I think you could set a variable saying what the class is, and then call a function as xsl:template match with the class as the arg. You would declare that function as xsl:template name, because you don't want to match on it automatically. Inside the function you should be able to script out those 100 values. Not sure whether this helps, but it organizes the code in a way that might.
精彩评论