Reputation: 585
I'm having problems with resolving variables in XSLT. I have a working XSL file with fixed values that I now want to make dynamic (the variale declarations will be move outside the XSL-file once it works). My current problem is to use variable $beginning in the starts-with function. This is the way all the googling has lead me to believe it should look, but it will not compile. It works how I use it in the substring-after function. How should this be done?
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="oldRoot" select="'top'" />
<xsl:variable name="beginning" select="concat('$.',$oldRoot)" />
<xsl:variable name="newRoot" select="'newRoot'" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="bind/@ref[starts-with(., $beginning)]">
<xsl:attribute name="ref">
<xsl:text>$.newRoot.</xsl:text><xsl:value-of select="$oldRoot"></xsl:value-of>
<xsl:value-of select="substring-after(., $beginning)" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2
Views: 927
Reputation: 70638
In XSLT 1.0 it is considered an error for a template match expression to contain a variable (See https://www.w3.org/TR/xslt#section-Defining-Template-Rules), so this line is failing
<xsl:template match="bind/@ref[starts-with(., $beginning)]">
(I believe some processors may allow it, but if they were following the spec, they shouldn't. It is allowed in XSLT 2.0 though).
What you can do is move the condition inside the template, and handle it with an xsl:choose
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="oldRoot" select="'top'" />
<xsl:variable name="beginning" select="concat('$.',$oldRoot)" />
<xsl:variable name="newRoot" select="'newRoot'" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="bind/@ref">
<xsl:choose>
<xsl:when test="starts-with(., $beginning)">
<xsl:attribute name="ref">
<xsl:text>$.newRoot.</xsl:text><xsl:value-of select="$oldRoot"></xsl:value-of>
<xsl:value-of select="substring-after(., $beginning)" />
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2