Reputation: 23
I am new to XSLT and spent a fair amount of time getting to grips with creating an in-line look up map to replace a specific value with another value for a mapped list in XSLT 2.0 only to find out I can only use 1.0. :-(
My question is how can a replicate the below working XSLT 2.0 code in 1.0. I have tried a few things but can't seem to get it working.
Point to note that if there is no map then the element should be empty.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="mapxml" >
<map>
<Country>
<input value="GB">RZ</input>
<input value="FR">TH</input>
</Country>
</map>
</xsl:variable>
<xsl:variable name="vMap"
select="$mapxml" />
<xsl:key name="kInputByVal" match="input"
use="@value" />
<xsl:template match="Country/text()">
<xsl:sequence select=
"(key('kInputByVal', ., $vMap/*/Country)[1]/text()
)[1]
"/>
</xsl:template>
</xsl:stylesheet>
Input XML:
<user>
<Country>GB</Country>
<Name>FOO</Name>
<Address>BAR</Address>
<user>
Upvotes: 2
Views: 5111
Reputation: 116992
Keys in XSLT 1.0 work only in the current document. In order to use a key to lookup from the stylesheet itself, you must switch the context to the stylesheet before using the key:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://example.com/my"
exclude-result-prefixes="my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="input-by-value" match="input" use="@value" />
<my:map>
<input value="GB">RZ</input>
<input value="FR">TH</input>
</my:map>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Country/text()">
<xsl:variable name="value" select="." />
<!-- switch context to stylesheet in order to use key -->
<xsl:for-each select="document('')">
<xsl:value-of select="key('input-by-value', $value)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2
Reputation: 338208
Here is the equivalent XSLT 1.0 program:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://tempuri.org/dummy"
exclude-result-prefixes="my"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<my:config>
<map>
<Country>
<input value="GB">RZ</input>
<input value="FR">TH</input>
</Country>
</map>
</my:config>
<xsl:variable name="vCountryMap" select="document('')/*/my:config/map/Country/input" />
<xsl:template match="Country/text()">
<xsl:value-of select="$vCountryMap[@value = current()]" />
</xsl:template>
</xsl:stylesheet>
Notes:
http://tempuri.org/dummy
is perfectly all-right.<xsl:strip-space elements="*" />
instructs the XSLT processor to ignore insignificant whitespace in the input. This helps in creating neatly indented output.document('')
refers to the XSLT stylesheet itself. You could also keep the configuration in an extra XML file, if you wanted to.exclude-result-prefixes
prevents the leaking of our temp namespace to the output.current()
refers to the node the XSLT processor is currently handling. ($vCountryMap[@value = .]
would not work, because here the .
refers to the XPath context, i.e. the <input>
nodes.)Upvotes: 4