RE: [xsl] How to do... regular 1 to n loops, 0 instead of null, maximum element, call template succinctly, etc.

Subject: RE: [xsl] How to do... regular 1 to n loops, 0 instead of null, maximum element, call template succinctly, etc.
From: "Michael Kay" <mhk@xxxxxxxxx>
Date: Tue, 23 Mar 2004 13:09:14 -0000
# 
# There are a few problems I have found hard to do using XSL 
# that I have some dodgy workarounds for, but I expect some 
# more experienced people will know a better way.

In XSLT 1.0 your dodgy workarounds may be the best answer there is, but all
of these have easy solutions in 2.0

# 
# 1) How to do regular programming loops, like for i = 1 to 10 
# For example I needed to do this recently to do a 16x16 grid 
# to display a class C network. I can only see how to loop on 
# XML nodes, so I had to create a nodeset like:
# <rows><row/><row/>....<row/></rows>


XSLT 2.0 allows <xsl:for-each select="1 to 10">


# 
# 2) When a node doesn't exist I want to get zero instead of 
# null A good solution seems to be to use sum(...), but this 
# only works if you pass it a nodeset. Sometimes I'm inside a 
# template that may be passed a nodeset or maybe a number. The 
# simplest way I figured then was number(concat('0', ...)) but 
# this seems less than ideal.


XPath 2.0 allows "(@path, 0)[1]" or "if (@path) then @path else 0" 

# 
# 3) How to get maximum element of a list? (or minimum) Best 
# solution found was something like the following, which seems 
# quite long and complicated:
# <xsl:variable name="max">
# <xsl:for-each select="nodes">
# <xsl:sort order="descending"/>
# <xsl:if test="position() = 1"><xsl:value-of 
# select="text()"/></xsl:if> </xsl:for-each> </xsl:variable>


XPath 2.0 allows max(nodes)


# 
# 4) How to succinctly call templates with parameters?
# Is there a neat and short way to call a template? The 
# following seems awfully long-winded:
# <xsl:call-template name="show-trend">
# <xsl:with-parameter name="curval">10</xsl:with-parameter>
# <xsl:with-parameter name="prevval">1</xsl:with-parameter>
# </xsl:call-template>
# I'd love to be able to do:
# <xsl:call-template name="show-trend" curval="10" 
# prevval="1"/> But that doesn't work :-( Any workarounds?
# 

XSLT 2.0 allows <xsl:function name="f"> in the stylesheet, which declares a
function that can be called from XPath as f(a,b,c)


# 5) How to sort so nulls come at top not bottom?
# Say I have <fred size="10"/><fred size="11"/><fred/> If you 
# use <xsl:sort select="@size"/> then the fred with no size 
# comes at the end. How can I make it come at the beginning?
# 

XQuery allows you to specify directly that nulls (empty sequences) are
sorted last rather than first. XSLT 2.0 doesn't provide this capability
directly; but you can always add an extra sort key

<xsl:sort select="empty(@x)"/>
<xsl:sort select="@x"/>

Since false sorts before true, this will cause elements having an @x
attribute to sort before elements not having one. You can use much the same
solution in 1.0, but use select="count(@x)" order="descending".

Michael Kay

Current Thread