xslt keep multiple variables in scope depending on a single test

2.2k Views Asked by At

I have many variables and only two cases. My original approach goes out of scope:

<xsl:choose>
    <xsl:when test='$something = 6'>
        <xsl:variable name="foo">x</xsl:variable>
        <!-- 50 other variables -->
    </xsl:when>
    <xsl:when test='$something = 7'>
        <xsl:variable name="foo">y</xsl:variable>
        <!-- 50 other variables -->
    </xsl:when>
</xsl:choose>

ie. later, with saxon, XPST0008: Variable x has not been declared (or its declaration is not in scope)

I think it would work if I would choose inside an xsl:variable tag, but then the tests would be repeated over and over and over and over and over:

<xsl:variable name="foo">
    <xsl:choose>
      <xsl:when test='$something = 6'>x</xsl:when>
      <xsl:when test='$something = 7'>y</xsl:when>
    </xsl:choose>
</xsl:variable>
<!-- 50 other variables, the two tests repeated for each... -->

Is there a way to keep the variables in scope but also don't repeat myself?


update 1

adding the complete 'sscce' files on request

original approach:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet  version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <xsl:variable name="something">6</xsl:variable>
    <xsl:choose>
        <xsl:when test="$something = '6'">
            <xsl:variable name="foo">x</xsl:variable>
            <!-- 50 other variables -->
        </xsl:when>
        <xsl:when test="$something = '7'">
            <xsl:variable name="foo">y</xsl:variable>
            <!-- 50 other variables -->
        </xsl:when>
    </xsl:choose>
    <xsl:value-of select="$foo"/>
</xsl:template>
</xsl:stylesheet>

approach that works but forces to repeat myself:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet  version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
    <xsl:variable name="something">6</xsl:variable>
    <xsl:variable name="foo">
        <xsl:choose>
          <xsl:when test='$something = 6'>x</xsl:when>
          <xsl:when test='$something = 7'>y</xsl:when>
        </xsl:choose>
    </xsl:variable>
    <!-- 50 other variables, the two tests repeated for each... -->
    <xsl:value-of select="$foo"/>
</xsl:template>
</xsl:stylesheet>

example xml file: <xml/>. example saxon command-line: java -jar saxon9he.jar -s:in.xml -xsl:in.xsl -o:out.html

2

There are 2 best solutions below

1
Welbog On

If you know your mappings beforehand, you can store them in their own file.

So instead of having something like this

<xsl:variable name="var1">
  <xsl:if test="something = 5">x</xsl:if>
</xsl:variable>
<xsl:value-of select="$var1"/>

You could have this

<xsl:value-of select="document('other.xml')/root/scheme[@number = 5]/@value"/>

With this as other.xml

<root>
  <scheme number="5" value="x"/>
  <scheme number="6" value="y"/>
</root>

You'll probably want a more complex other.xml, with various groups of colours for each colour scheme, but the idea would be the same, and avoids tests and variables completely.

0
potame On

Well, I'd rather process that way :

<xsl:variable name="something">6</xsl:variable>

<xsl:variable name="var.set">
  <xsl:choose>
    <xsl:when test="$something = '6'">
        <foo>x</foo>
        <bar>xx</bar>
        <!-- 50 other variables, to be inserted as tag -->
    </xsl:when>
    <xsl:when test="$something = '7'">
        <foo>y</foo>
        <bar>yy</bar>
        <!-- 50 other variables, to be inserted as tag -->
    </xsl:when>
  </xsl:choose>
</xsl:variable>

The variable var.set will be a nodeset that you will be able to read thanks to the exsl:node-set() extension.

For example to retrieve the value for foo (stored as a node and not as a variable anymore), use something like: <xsl:value-of select="exsl:node-set($var.set)/foo" />. Like this you will handle a single variable, quite as if it were an array of values.

PS: on the root tag of your stylesheet, do not forget to add the exsl namespace declaration xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"