I recently had the need to output a SELECT HTML element with a list of states. My initial approach was simple where I used <xsl:copy>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:custom="com.thebitguru" exclude-result-prefixes="custom">
	<xsl:output method="html" omit-xml-declaration="yes"/>
	<xsl:strip-space elements="*" />

	<custom:states>
		<option value="AL">Alabama</option>
		<!-- ... -->
		<option value="WI">Wisconsin</option>
		<option value="WY">Wyoming</option>
	</custom:states>

	<xsl:template match="option">
		<xsl:copy>
			<xsl:if test="@value = $val">
				<xsl:attribute name="selected">selected</xsl:attribute>
			</xsl:if>
			<xsl:attribute name="value"><xsl:value-of select="@value" /></xsl:attribute>
			<xsl:value-of select="." />
		</xsl:copy>
	</xsl:template>

	<xsl:template match="*">
		<label for="state">* State:</label>
		<select name="state" id="state">
			<xsl:apply-templates select="document('')/*/custom:states/option" />
		</select>
	</xsl:template>
</xsl:stylesheet>

The problem with this approach was that the option tags were printing the xml namespaces, even with the exclude-result-prefixes="custom" specified (because that attribute does not apply to <xsl:copy>).

1
2
3
4
<option value="AL" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="com.thebitguru">Alabama</option>
...
<option value="WI" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="com.thebitguru">Wisconsin</option>
<option value="WY" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:custom="com.thebitguru">Wyoming</option>

I didn’t want these namespaces in the output so after some searching and reading through the docs I decided to create new elements using the <xsl:element> tags instead, especially since the tag that I was copying was very small.

1
2
3
4
5
6
7
8
9
<xsl:template match="option">
	<xsl:element name="option">
		<xsl:if test="@value = $val">
			<xsl:attribute name="selected">selected</xsl:attribute>
		</xsl:if>
		<xsl:attribute name="value"><xsl:value-of select="@value" /></xsl:attribute>
		<xsl:value-of select="." />
	</xsl:element>
</xsl:template>

There are other ways to accomplish the same thing, e.g. copy-namespaces in XSLT 2.0, but in my case I was stuck with XSLT 1.0.

Back to blog...