[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Using the f:xsltSort() function of FXSL for dynamic s

Subject: Using the f:xsltSort() function of FXSL for dynamic sorting (Was: Re: Dynamically define number of xsl:sort stmts using parameters)
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Wed, 28 Mar 2007 22:46:59 -0700
 Using the f:xsltSort() function of FXSL for dynamic  s
Here's how one can use the FXSL function

f:xsltSort()

This transformation:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="xs f"


<xsl:import href="../f/func-map.xsl"/> <xsl:import href="../f/func-flip.xsl"/> <xsl:import href="../f/func-standardXSLTXpathFunctions.xsl"/> <xsl:import href="../f/func-standardAxisXpathFunctions.xsl"/>

<!--
 To be applied on testFunc-xsltSort2.xml
-->

<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:template match="/">
 <employees>
  <xsl:sequence select=
    "f:xsltSort(/*/employee,
                      f:map(f:flip(f:element()), /*/sort)
                     )"/>
 </employees>
</xsl:template>
</xsl:stylesheet>

when applied on this source xml document:

<employees>
 <employee hireDate="04/23/1999">
   <last>Hill</last>
   <first>Phil</first>
   <salary>089000</salary>
 </employee>

 <employee hireDate="09/01/1998">
   <last>Herbert</last>
   <first>Johnny</first>
   <salary>095000</salary>
 </employee>

 <employee hireDate="08/20/2000">
   <last>Hill</last>
   <first>Graham</first>
   <salary>100000</salary>
 </employee>



 <sort order="1">last</sort>
 <sort order="3">salary</sort>
 <sort order="3">first</sort>
</employees>

produces the wanted result:

<employees>
  <employee hireDate="09/01/1998">
     <last>Herbert</last>
     <first>Johnny</first>
     <salary>095000</salary>
 </employee>
  <employee hireDate="04/23/1999">
     <last>Hill</last>
     <first>Phil</first>
     <salary>089000</salary>
 </employee>
  <employee hireDate="08/20/2000">
     <last>Hill</last>
     <first>Graham</first>
     <salary>100000</salary>
 </employee>
</employees>


Here is the code of the function f:xsltSort():


<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="xs f"


<xsl:import href="func-map.xsl"/> <xsl:import href="func-flip.xsl"/>

<!--
      XSLT functions:
                    xsltSort()
-->

<xsl:function name="f:xsltSort" as="item()*">
  <xsl:param name="pSeq" as="item()*"/>
  <xsl:param name="pCriteria" as="node()*"/>

  <xsl:perform-sort select="$pSeq">
    <xsl:sort select=
         "string-join(
                      f:map(f:flip(f:map(), .), $pCriteria)
                      ,
                      ''
                      )
         "
    />
  </xsl:perform-sort>
</xsl:function>

</xsl:stylesheet>


The $pSeq argument contains the sequence of items to be sorted.


The $pCriteria argument is a sequence of functions (template
references), each of which produces a (xs:string) part of the sort
key, when this (sort-key-part-generating)function is applied to the
current item of the sequence $pSeq .

Then all such sort-key parts are string-join()-ed to produce the
complete sort key of the current item of the sequence $pSeq  being
sorted. Because their results are concatenated from left to right, a
function, which is specified to the left of another function in the
sequence $pCriteria has higher priority in determining the sort order
of any two items of $pSeq.


The function f:element() used in the test code is an accessor function.


f:element($pNode, $someStrName)

produces the sequence:

$pNode/*[name() = $someStrName]


All functions described can be downloaded from the latest FXSL CVS.



-- Cheers, Dimitre Novatchev --------------------------------------- Truly great madness cannot be achieved without significant intelligence. --------------------------------------- To invent, you need a good imagination and a pile of junk ------------------------------------- You've achieved success in your field when you don't know whether what you're doing is work or play



On 3/28/07, Angela Williams <Angela.Williams@xxxxxxxxxxxxxxxxxx> wrote:
Aha!

My esteemed colleague came up with a better idea - gosh, I hate it when
I forget the power of xpath!

<?xml version="1.0" encoding="UTF-8"?>
<employees>
 <employee hireDate="04/23/1999">
   <last>Hill</last>
   <first>Phil</first>
   <salary>100000</salary>
 </employee>

 <employee hireDate="09/01/1998">
   <last>Herbert</last>
   <first>Johnny</first>
   <salary>95000</salary>
 </employee>

 <employee hireDate="08/20/2000">
   <last>Hill</last>
   <first>Graham</first>
   <salary>89000</salary>
 </employee>

 <sort order="1">last</sort>
 <sort order="2">first</sort>
</employees>

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0" xmlns:saxon="http://saxon.sf.net/">

<xsl:output method="text" />

 <xsl:template match="employees">
   <xsl:variable name="sort1" select="sort[@order='1']" />
   <xsl:variable name="sort2" select="sort[@order='2']" />
   <xsl:variable name="sort3" select="sort[@order='3']" />
   <xsl:variable name="sort4" select="sort[@order='4']" />

   <xsl:for-each select="employee">
     <xsl:sort
         select="if ($sort1) then saxon:evaluate($sort1) else 'foo'" />
     <xsl:sort
         select="if ($sort2) then saxon:evaluate($sort2) else 'foo'" />
     <xsl:sort
         select="if ($sort3) then saxon:evaluate($sort3) else 'foo'" />
     <xsl:sort
         select="if ($sort4) then saxon:evaluate($sort4) else 'foo'" />


Last: <xsl:apply-templates select="last" /> First: <xsl:apply-templates select="first" /> Salary: <xsl:apply-templates select="salary" /> Hire Date: <xsl:apply-templates select="@hireDate" /> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>

-----Original Message-----
From: Angela Williams
Sent: Tuesday, March 27, 2007 12:59 PM
To: 'xsl-list@xxxxxxxxxxxxxxxxxxxxxx'
Subject: RE:  Dynamically define number of xsl:sort stmts using
parameters

Thanks for both of your quick responses.  You've confirmed I am on the
right path.  There is a lot to think about.

Charles Knell wrote:
>use a stylesheet to create a stylesheet that does the transformation.

I think this would be possible, if complicated.  The user is not limited
on the number of tables they can insert, so there could be several
templates generated. It seems I would still end up with a variation of
3, as I would want to consolidate the number of templates to a minimum,
since the user could specify multiple tables with the same number of
sort statements. This would also mean I would have to output the master
stylesheet on the fly, too, to get the list of includes correct.

> (Do your users check off the columns they want to sort by in some user
>interface?

Yes.

Abel Braaksma wrote:
> 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.

This would certainly be the most expedient solution in the short term.

Again,
Thanks!

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.