p2p.wrox.com Forums

p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   XSLT (http://p2p.wrox.com/forumdisplay.php?f=86)
-   -   Sorting & Limiting a for-each (top most recent) (http://p2p.wrox.com/showthread.php?t=32423)

BeneathClouds August 12th, 2005 01:41 AM

Sorting & Limiting a for-each (top most recent)
 
Hello,

What I am effectively trying to achieve is sorting a group of elements, then from this sorted grouping return the top 5 elements.

Cut down version of the XML is:

Code:

<customfield name="WhatsNew">
    <pages>
        <listitem>
              <title>Wrox books are cool</title>
              <url>/theforums/aregreat/</url>
            <doc-dates>
                <published-date>2005-07-29T15:02:52.9800000+10:00</published-date>
            </doc-dates>
        </listitem>
        <listitem>
              <title>Wrox books are cool</title>
              <url>/theforums/aregreat/</url>
            <doc-dates>
                <published-date>2005-08-29T15:02:52.9800000+10:00</published-date>
            </doc-dates>
        </listitem>
    </pages>
    <sections>
        <listitem>
              <title>Wrox books are cool</title>
              <url>/theforums/aregreat/</url>
            <doc-dates>
                <published-date>2005-03-29T15:02:52.9800000+10:00</published-date>
            </doc-dates>
        </listitem>
    </sections>
<customfield>

A cut down version of what I was trying was:

Code:

<xsl:for-each select="//customfield[@name='WhatsNew']/node()/listitem">
    <xsl:sort select="doc-dates/published-date" order="descending" />
    <xsl:if test="position() &lt; 6">
        <xsl:variable name="day" select="substring(doc-dates/published-date,9,2)" />

        <a>
            <xsl:attribute name="href">
                <xsl:value-of select="url"/>
            </xsl:attribute>
            <xsl:value-of select="title"/>
        </a> - <xsl:value-of select="$day"/>
    </xsl:if>
</xsl:for-each>

Now from what I can tell "position()" only refers the the position of the element within the XML not within the 'sorted' version of it.

Any suggestions would be much appreciated!!!! [B)]


mhkay August 12th, 2005 02:39 AM

Your design approach looks fine. Within a sorted for-each, position() refers to the position in sorted order.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference

joefawcett August 13th, 2005 04:43 AM

As Michael said it looks fine, perhaps your dates are not all in the same time zone so the sort will not function as planned?

--

Joe (Microsoft MVP - XML)

BeneathClouds August 16th, 2005 12:35 AM

My apologies, upon testing this again everything work correctly.

I can only assume amongst all of the changes I have been making I made some clumsy version error. [:I]

Many thanks!! [^]

Mystwalker October 6th, 2005 06:31 PM

Hi there,

I also used sorting to get the maximum values - the top three, to be specific.
But I have two issues:

1. I have to change the commands to also consider negative values - sorting should be done using absolute values.
Is this possible with the sort function? Or do I have to take a different approach?

2. I currently have a sub-optimal approach, as I use the code below six times in a row to create variables holding the top three and the resp. values.

(The important part of) the XML file looks like this:

Code:

<arrayLine Name="abc">
<arrayField Name="F1">13.491</arrayField>
<arrayField Name="F2">12.023</arrayField>
<arrayField Name="F3">1.676</arrayField>
<arrayField Name="F4">-33.884</arrayField>
<arrayField Name="F5">11.592</arrayField>
<arrayField Name="F6">9.291</arrayField>
<arrayField Name="F7">1.743</arrayField>
</arrayLine>
<arrayLine Name="xyz">
<arrayField Name="F1">21.433</arrayField>
<arrayField Name="F2">4.326</arrayField>
<arrayField Name="F3">12.891</arrayField>
<arrayField Name="F4">0.150</arrayField>
<arrayField Name="F5">10.471</arrayField>
<arrayField Name="F6">23.803</arrayField>
<arrayField Name="F7">14.555</arrayField>
</arrayLine>
...

I have to get the top three values for a given "Fn" from all arrayLine's and the names of the resp. arrayLine's.
In the example code above, it would be
for F1:
topOne = xyz
topOneValue = 21.433
topTwo = abc
topTwoValue = 13.491

for F4:
topOne = abc
topOneValue = -33.884
topTwo = xyz
topTwoValue = 0.150

The corresponding code snippet for getting topOne:
Code:

<xsl:variable name="topOne">
    <xsl:for-each select="arrayLine/arrayField[@Name=$currentFactor]">
        <xsl:sort data-type="number" order="descending"/>
        <xsl:if test="position()=1">
            <xsl:value-of select="../@Name"/>
        </xsl:if>
        </xsl:for-each>
</xsl:variable>

($currentFactor gets iterated from F1 to F7)

Could you please give me advise how to do this?
Thanks in advance! :)

Cheers,
Dennis

P.S.: Is it possible to only take a fixed number of digits after the decimal point?

mhkay October 7th, 2005 02:59 AM

To sort on absolute numeric value:

In XSLT 2.0 use

<xsl:sort select="abs(XXX)"/>

In XSLT 1.0 use

<xsl:sort select="translate(XXX, '-' '')" data-type="number"/>

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference

Mystwalker October 8th, 2005 05:45 PM

Quote:

quote:<xsl:sort select="translate(XXX, '-' '')" data-type="number"/>
That did the job. Thanks, Michael!

I didn't know that XSLT 2.0 isn't widely supported so far. :(

Quote:

quote:Now from what I can tell "position()" only refers the the position of the element within the XML not within the 'sorted' version of it.
Actually, it seems to refer to the sorted version for me...


mhkay October 8th, 2005 06:02 PM

As mentioned in my first posting in this thread (dated 08/12/2005 - I think it must mean 12th August), within the body of an xsl:for-each, position() refers to the position in sorted order.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference


All times are GMT -4. The time now is 12:15 PM.

Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.