Re: [xsl] Dynamically define number of xsl:sort stmts using parameters

Subject: Re: [xsl] Dynamically define number of xsl:sort stmts using parameters
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Tue, 27 Mar 2007 17:52:10 +0200
Angela Williams wrote:
Good morning, list -

good evening for me ;)





  <sort order="1">name</sort>
  <sort order="2">city</sort>
I can think of the following theoretical solutions, but I don't know if they are even possible:

1. (I know this doesn't work) Create multiple variables to evaluate the sort value and then hardcode the same number of <xsl:sort> statements that may be evaluating a null value for @select:


2. Use xsl to select the sort nodes and then dynamically write and output the template and for-each loop that uses the appropriate number of sort statements - then how would I call it in the same stylesheet?


3. Write multiple templates using 0 to n sort statements and then call the appropriate template based on the number of <sort/> nodes found? This doesn't sound very elegant or practical to me, but might be the simplest...

Any suggestions?

I looked up an old template of myself where I faced a similar problem. The easy part is the number of sort statements. Just limit the amount to, say, 10, and create 10 sort statements. Then:


1. The 'order' and 'data-type' are AVT, so you can easily get them from any variable or data structure. Likely something like: $sortkeys/sort[1]/order etc. This will give you fine granularity control over descending/ascending, numeric/string. Keep in mind that it is an error when the order or data-type evaluates to empty, so make sure to use defaults in that case.

2. The select statements are a bit tricky. You can leave them simple if you only need to sort on one node with a given name (from your sortkey) and use local-name() or name() functions to match for it. You can evaluate an xpath (not sure saxon:evaluate is the way to go) or you can decide to create a simple function that takes the current node and resolves your (simplified) xpath if it is more then just a node name.

3. The order of the sortkeys is something you can resolve in several XSLT native ways. That shouldn't be that hard.

Combined, this looks something like this:

<!-- order of these elements is the order for the sort-key -->
<xsl:variable name="sortkey">
  <key nodename='name' order='ascending' type='string' />
  <key nodename='street' order='ascending' type='string' />
  <key nodename='birth-year' order='ascending' type='numberic' />
</xsl:variable>

<xsl:apply-templates select="somenode">
<xsl:sort select="*[local-name() = $sortkey/key[1]/@nodename"
order="{$sortkey/key[1]/@order}" data-type="{$sortkey/key[1]/@type}"/>
<xsl:sort select="*[local-name() = $sortkey/key[1]/@nodename"
order="{$sortkey/key[2]/@order}" data-type="{$sortkey/key[2]/@type}"/>
<xsl:sort select="*[local-name() = $sortkey/key[1]/@nodename"
order="{$sortkey/key[3]/@order}" data-type="{$sortkey/key[3]/@type}"/>
.... etc (10x) ...
</xsl:apply-templates>



You can generalize this to some further extend, of course.


If you want even more control, you should consider making a two-pass transformation where in the first pass you create the XSLT that contains the correct sortkeys. FXSL has many examples of how to do multi-pass on XSLT alone.

HTH,

Cheers,
-- Abel Braaksma
  http://www.nuntia.nl

Current Thread