Reference a nodeset without copying it

Deep inside a stylesheet, I have some logic that looks sort of like this:

<xsl:variable name="v1">
    <!-- define structure within v1 -->
</variable>
<xsl:variable name="v2">
    <!-- define structure within v2 -->
</variable>
<xsl:variable name="valuesMap" select="exsl:node-set($v1)"/>
<xsl:variable name="valuesMap_2" select="exsl:node-set($v2)"/>
...
<xsl:variable name="tmp">
    <xsl:choose>        
        <xsl:when test="$isSomeCondition">
            <xsl:copy-of select="$valuesMap"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="$valuesMap_2"/>
        </xsl:otherwise>
     </xsl:choose>
 </xsl:variable>
 <xsl:variable name="valueSet" select="exsl:node-set($tmp)"/>
 <xsl:choose>
    <xsl:when test="not($valueSet/Child[@someAttribute=$someOtherVariable])">
       ...
    </xsl:when>
    ...

The variables $valuesMap and $valuesMap_2 are variables that contain node sets. They are defined elsewhere and are referenced several places in this transformation.

What I am trying to do is check a condition ($isSomeCondition) and then set a local variable, $valueSet, to refer to either $valuesMap or $valuesMap_2. I'm doing this because there are several places in this template where I need to choose between $valuesMap or $valuesMap_2 and I'd rather just make the decision once and use a local variable to keep track of it.

The code above works, but I'm concerned about using copy-of: I fear it will completely duplicate the contents of $valuesMap or $valuesMap_2, and that could be a problem because these variables could contain some rather large structures and this specific template will be used numerous times per transformation.

I've already tried using value-of but that seems to capture the text content of the variables, not the XML structure.

Is there any way to reference the correct structure without having to copy it?

Upvotes: 2

Views: 44

Answers (2)

I found an alternate solution using the "evaluate" function in then "dynamic" package of EXSLT:

<xsl:variable name="tmpName">
    <xsl:choose>        
        <xsl:when test="$isSomeCondition">
            <xsl:text>$valuesMap</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>$valuesMap_2</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>
<xsl:variable name="valueSet" select="dyn:evaluate($tmpName)"/>
 <xsl:choose>
    <xsl:when test="not($valueSet/Child[@someAttribute=$someOtherVariable])">
       ...
    </xsl:when>
    ...

On the other hand, this uses an eval function... I'd guess that Ian's still performs better than this, ...and I'd guess that this solution probably performs better than my original problem which used copy-of.

Upvotes: 0

Ian Roberts
Ian Roberts

Reputation: 122394

Combine the two variables into one, e.g.

<xsl:variable name="vMapRTF">
  <v1>
    <!-- define structure within v1 -->
  </v1>
  <v2>
    <!-- define structure within v2 -->
  </v2>
</xsl:variable>

<xsl:variable name="vMap" select="exsl:node-set($vMapRTF)" />

<xsl:variable name="valueSet" select="$vMap/*[2 - $isSomeCondition]" />

Here I'm taking advantage of the fact that a boolean expression in a numeric context is treated as 0 if it's false and 1 if it's true, so if $isSomeCondition is true it'll pick $vMap/*[1] (the v1 element) and if it's false it'll pick $vMap/*[2].

If you still need the separate $valuesMap and $valuesMap_2 variables for use elsewhere in the transformation then just declare them as e.g.

<xsl:variable name="valuesMap" select="$vMap/v1" />

Upvotes: 3

Related Questions