Subject: Re: [xsl] Re: Dynamic number of sort key component? From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Fri, 14 May 2010 09:59:43 -0700 |
Here is a non-recursive, XSLT 1.0 solution. It assumes that the maximum possible number of sort keys is statically known, and specifies the maximum possible number of sort keys: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <my:sortKeys> <key value="a" order="descending"/> <key value="c" order="ascending"/> </my:sortKeys> <xsl:variable name="vSortKeys" select= "document('')/*/my:sortKeys/*"/> <xsl:template match="/*"> <xsl:for-each select="row"> <xsl:sort select="col[@name=$vSortKeys[1]/@value]" order="{$vSortKeys[1]/@order}"/> <xsl:sort select="col[@name=$vSortKeys[2]/@value]" order="{$vSortKeys[2]/@order}"/> <xsl:sort select="col[@name=$vSortKeys[3]/@value]" order="{$vSortKeys[3]/@order}"/> <xsl:sort select="col[@name=$vSortKeys[4]/@value]" order="{$vSortKeys[4]/@order}"/> <xsl:sort select="col[@name=$vSortKeys[5]/@value]" order="{$vSortKeys[5]/@order}"/> <xsl:sort select="col[@name=$vSortKeys[6]/@value]" order="{$vSortKeys[6]/@order}"/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet> When this transformation is applied on this XML document: <table> <row> <col name="a">1</col> <col name="b">2</col> <col name="c">3</col> <col name="d">4</col> </row> <row> <col name="a">2</col> <col name="b">bli</col> <col name="c">1</col> <col name="d">blu</col> </row> </table> the wanted, correct result is produced: <row> <col name="a">2</col> <col name="b">bli</col> <col name="c">1</col> <col name="d">blu</col> </row> <row> <col name="a">1</col> <col name="b">2</col> <col name="c">3</col> <col name="d">4</col> </row> -- Cheers, Dimitre Novatchev --------------------------------------- Truly great madness cannot be achieved without significant intelligence. --------------------------------------- To invent, you need a good imagination and a pile of junk ------------------------------------- Never fight an inanimate object ------------------------------------- You've achieved success in your field when you don't know whether what you're doing is work or play On Fri, May 14, 2010 at 7:22 AM, Michael Kay <mike@xxxxxxxxxxxx> wrote: > > Try something like this: > > <xsl:function name="f:sort" as="element(row)*"> > B <xsl:param name="data" as="element(row)"/> > B <xsl:param name="sortColumnNames" as="xs:string*"/> > B <xsl:param name="sortAscDesc" as="xs:string*"/> > B <xsl:variable name="sorted" as="element(row)"> > B B <xsl:perform-sort select="$data"> > B B B <xsl:sort select="*[name()=$sortColumnNames[last()]" > B B B B B B B B order="{$sortAscDesc[last()]}" stable="yes"/> > B B </xsl:perform-sort> > B <xsl:variable> > B <xsl:sequence select="if (count($sortColumnNames) eq 1 > B B B B B B B B B B B B then $sorted > B B B B B B B B B B B B else f:sort($sorted, subsequence($sortColumnNames, > 2), subsequence($sortAscDesc, 2))"/> > </xsl:function> > > Those with grey hair will recognize this as the multi-phase sort process > used by punched card operators, sorting first by the last sort key, then the > last-but-one, and so on. > > Regards, > > Michael Kay > http://www.saxonica.com/ > http://twitter.com/michaelhkay > >> -----Original Message----- >> From: Fabre Lambeau [mailto:fabre.lambeau@xxxxxxxxx] >> Sent: 14 May 2010 14:46 >> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx >> Subject: [xsl] Re: Dynamic number of sort key component? >> >> I'm writing a tool that allows my users to query an XML >> document a-la-SQL (but simplified). >> For example, given an XML document such as: >> >> <table> >> B <row> >> B B <col name="a">1</col> >> B B <col name="b">2</col> >> B B <col name="c">3</col> >> B B <col name="d">4</col> >> B </row> >> B <row> >> B B <col name="a">bla</col> >> B B <col name="b">bli</col> >> B B <col name="c">blo</col> >> B B <col name="d">blu</col> >> B </row> >> B <!-- ... --> >> </table> >> >> I'd like them to be able to say something like: >> SELECT a,b,c,d >> ORDER BY a ASC,b DESC >> GROUP BY a,c,d >> >> My component (XSLT stylesheet) takes that query and >> effectively processes it in XSLT. >> The GROUP BY statement is easy to process, since I can just >> concatenate the values for the corresponding <col> elements, >> and use that string as a key to a for-each-group. >> However, I can't find a way to do the sorting (for which the >> order is different for each individual column). >> >> What I seem to need is the ability to have a dynamic number >> of sort key components, which as far as I know is not >> possible The following is obviously not possible: >> <xsl:perform-sort select="col"> >> B <xsl:for-each select="tokenize($group-by, ',')"> >> B B <xsl:sort select="col[@name=string-before(current(),' ']) >> order="{string-after(current(),' ']}ending"/> >> B </xsl:for-each> >> </xsl:perform> >> >> Can anyone think of a way to do this (whilst retaining the >> ability to have a dynamic list of ORDER BY columns, each one >> specifying its own order)? >> Unfortunately, I don't think I have the ability to generate a >> separate XSLT sheet after parsing the query string and >> execute it, as my engine is all in XSLT (executed with AltovaXML) >> >> -- >> Fabre Lambeau
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Re: Dynamic number of sor, Michael Kay | Thread | Re: [xsl] Re: Dynamic number of sor, Fabre Lambeau |
RE: [xsl] xslt 2.1 saxon:discard-do, Michael Kay | Date | [xsl] Namespace handling question, Bridger Dyson-Smith |
Month |