Reputation: 1483
<xsl:variable name="map">
<map>
<item key="Name" value="John"/>
<item key="Address" value="Un_Known"/>
<item key="Phone" value="(878)876678"/>
<item key="Last Name" value="Verner"/>
</map>
</xsl:variable>
<xsl:for-each select "$map/map/item">
<xsl:if test="./@key = $input">
<!-- cool user is asking for something know .. do something fancy -->
</xsl:if>
<xsl:for-each>
I want to declare a map like structure in my XSLT and then want to access it. Apparently, I would like not to use extra name spaces so using exsl:node-set is not the solutions I am looking for right-now.
I am using XSLT 1.0 Saxon.
Is there a better way to do what I am trying to do ?
Thanks Karephul
All the below mentioned answers are correct and valid. We finally decided to use the "exsl:node-set"
Upvotes: 2
Views: 2495
Reputation: 243449
You got three very good answers.
Here is another, that demonstrates how to use keys to access a lookup table (which in practical cases would reside in a separate XML document):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pInput" select="'Phone'"/>
<my:map>
<item key="Name" value="John"/>
<item key="Address" value="Un_Known"/>
<item key="Phone" value="(878)876678"/>
<item key="Last Name" value="Verner"/>
</my:map>
<xsl:key name="kLookup" match="item/@value" use="../@key"/>
<xsl:template match="/">
<xsl:for-each select="document('')">
<xsl:value-of select="key('kLookup', $pInput)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to any XML document (not used), the wanted, correct result is produced:
(878)876678
In XSLT 2.0 the xsl:for-each
isn't needed, because the key()
function accepts a third argument that specifies the document to be indexed:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pInput" select="'Phone'"/>
<my:map>
<item key="Name" value="John"/>
<item key="Address" value="Un_Known"/>
<item key="Phone" value="(878)876678"/>
<item key="Last Name" value="Verner"/>
</my:map>
<xsl:key name="kLookup" match="item/@value" use="../@key"/>
<xsl:template match="/">
<xsl:value-of select="key('kLookup', $pInput, document(''))"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 163322
If you are using Saxon, then it is very hard to see why you are still using XSLT 1.0. This kind of thing (and many other things) are much easier in XSLT 2.0 - it's time you moved forward.
Upvotes: 2
Reputation: 66723
You can include extra XML information, like your <map>
directly in your XSLT. That XML data will need to be bound to a namespace (other than the XSLT namespace), but it can be any namespace.
You can access the data within the XSLT by using the document()
function with an empty string, which will load the XSLT document.
Incidentally, you can eliminate the need for the <xsl:if>
by using a predicate filter on the XPath of your xsl:for-each
select.
For instance:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:my="http://stackoverflow.com/questions/12146687/creating-a-map-in-xlst">
<xsl:param name="input" />
<my:map >
<item key="Name" value="John"/>
<item key="Address" value="Un_Known"/>
<item key="Phone" value="(878)876678"/>
<item key="Last Name" value="Verner"/>
</my:map>
<xsl:template match="/">
<xsl:for-each select="document('')/*/my:map/item[@key=$input]">
<!-- cool user is asking for something know .. do something fancy -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 27994
If you don't want to use the node-set()
extension function, you can put your <map>
data in a separate XML file, e.g. map.xml
. Then access that file from your stylesheet using document('map.xml')
. You can then access the contents of the map using XPath expressions, as you showed above.
Upvotes: 1