Looping over hard-coded values in specified in XSL stylesheet, not in XML
I'm wondering if there's a way to loop over a values specified in the XSL, rather than coming from the XML.
Let's say I have 3 possible checkboxes, with a "current" value that comes from the XML. I'd have an XML doc like
<rootNode>
<val>bar</val>
</rootNode>
and XSL code like
<input id="foo" type="checkbox" name="myvar" value="foo">
<xsl:if test="val='foo'">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input> <label for="foo">foo</label>
<input id="bar" type="checkbox" name="myvar" value="bar">
<xsl:if test="val='bar'">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input> <label for="bar">bar</label>
<input id="baz" type="checkbox" name="myvar" value="baz">
<xsl:if test="val='baz'">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input> <label for="baz">baz</label>
This works, but the XSL is very verbose. I'd LIKE to be able to do something like this:
<!-- this syntax doesn't work, is there something similar that does? -->
<xsl:variable name="boxNames" select="'foo','bar','baz'"/>
<xsl:for-each select="name in $boxNames">
<input id="{$name}" type="checkbox" name="myvar" value="{$name}">
<xsl:if test="val=$name">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input> <label for="{$name}"><xsl:value-of select="$name"/></label>
</xsl:for-each>
I can KIND OF get this by putting the code in a template and using multiple <call-template>
<with-param>
calls, but that's doesn't开发者_C百科 save much space over the original.
Is there any concise way to do this with XSL? I definitely can't put all the checkbox names in the XML output, it's a large list and unnecessarily bloats the XML.
Yes, you can get the source (!) of the XSL by calling the document('')
function, which you can then use as node datasource.
<xsl:template name="boxNames"> <!-- not used as template -->
<name>foo</name>
<name>bar</name>
<name>baz</name>
</xsl:template>
[...]
<xsl:variable name="boxNames" select="document('')/xsl:stylesheet/xsl:template[@name='boxNames']/name" />
Try this, which is very close to the code you suggested:
<xsl:variable name="boxNames" select="'foo','bar','baz'"/>
<xsl:variable name="val" select="val"/>
<xsl:for-each select="$boxNames">
<input id="{.}" type="checkbox" name="myvar" value="{.}">
<xsl:if test="$val=.">
<xsl:attribute name="checked">checked</xsl:attribute>
</xsl:if>
</input> <label for="{.}"><xsl:value-of select="."/></label>
</xsl:for-each>
It needs an XSLT 2.0 processor though.
Template matches are effectively for-each loops.
<xsl:template match="/">
<xsl:apply-templates match="namespace:ItemName"/>
</xsl:template>
<xsl:template match="namespace:ItemName">
<input>
<xsl:attribute name="id"><xsl:value-of select="."></xsl:attribute>
<xsl:attribute name="type">checkbox</xsl:attribute>
<xsl:attribute name="name">myvar</xsl:attribute>
<xsl:attribute name="value"><xsl:value-of select="."></xsl:attribute>
<xsl:value-of select=".">
</input>
<label>
<xsl:attribute name="for"><xsl:value-of select="." /></xsl:attribute>
<xsl:value-of select="."/>
</label>
</xsl:template>
That should cut it down.
精彩评论