XSLT Variable Scoping Differences Across MSXML Versions

XSLT Add comments

Subtle differences in variable scoping in XSLTs between MSXML 3.0 and 4.0 can result in XSLT files breaking if you upgrade your version of MSXML. Consider the following XSLT:

<?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 match="/">
        <root>
            <elem>
                <xsl:variable name="foo">Value</xsl:variable>
                <xsl:value-of select="$foo" />
            </elem>
            <elem>
                <!-- This refers to the variable defined in
                     the previous sibling elem node -->
                <xsl:value-of select="$foo" />
            </elem>
        </root>
    </xsl:template>
</xsl:stylesheet>

This stylesheet (which does not depend on the input XML) works on MSXML 3.0 but fails on MSXML 4.0 with the error message

A reference to variable or parameter ‘foo’ cannot be resolved. The variable or parameter may not be defined, or it may not be in scope.

Clearly, MSXML 4.0 limits the scope of the foo variable to the first elem node, whereas MSXML 3.0 does not. I suspect MSXML 3.0 scopes a variable to its enclosing template.

These scoping differences cut both ways. Consider this attempt to fix the XSLT:

<?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 match="/">
        <root>
            <elem>
                <xsl:variable name="foo">Value</xsl:variable>
                <xsl:value-of select="$foo" />
            </elem>
            <elem>
                <xsl:variable name="foo">Value</xsl:variable>
                <xsl:value-of select="$foo" />
            </elem>
        </root>
    </xsl:template>
</xsl:stylesheet>

This stylesheet works on MSXML 4.0 but fails on MSXML 3.0 with the error message

Variable or parameter ‘foo’ cannot be defined twice within the same template.

If you want the stylesheet to work on both processors, you must push up the variable declaration as follows:

<?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 match="/">
        <root>
            <xsl:variable name="foo">Value</xsl:variable>
            <elem>
                <xsl:value-of select="$foo" />
            </elem>
            <elem>
                <xsl:value-of select="$foo" />
            </elem>
        </root>
    </xsl:template>
</xsl:stylesheet>

Be careful. Even the smallest of changes can break your software.

Comments are closed.

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in