 |
| XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
|
|
|
|

February 13th, 2006, 06:42 AM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Sorting problem (Paging)
Hi all,
I want to sort my results by a date attribute, but also break the results up into pages (18 per page). I have done all this but my sort only works for one page at a time. How can I sort all of the results first. Any help will be greatly appreciated.
XSL:
Code:
<xsl:template match="/">
<html>
<link rel="stylesheet" type="text/css" href="portfolio_style.css" />
<body>
<h1>Portfolio</h1>
<xsl:call-template name="pagination" />
<div id="portfolio">
<xsl:for-each select="portfolio/campaign[position() > $vFirstRecord][position() <= $pRecordsPerPage]">
<xsl:sort select="substring(@date,7,4)" order="descending"/>
<xsl:sort select="substring(@date,4,2)" order="descending"/>
<xsl:sort select="substring(@date,1,2)" order="descending"/>
<xsl:call-template name="campaign"/>
</xsl:for-each>
</div>
</body>
</html>
</xsl:template>
|
|

February 13th, 2006, 07:21 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
You want a two-phase transformation. Capture the results of the sort in a variable
<xsl:variable name="sorted-set">
<xsl:for-each>
<xsl:sort>
</xsl:variable>
and then group the result into pages:
<xsl:for-each select="xx:node-set($sorted-set)/*[position() mod $N = 1]">
<page>
<xsl:copy-of select=".|following-sibling::*[position() < $N]"/>
</page>
</xsl:for-each>
The xx:node-set() function is implementation-dependent; with XSLT 2.0 it isn't needed (and you can do the grouping a bit more elegantly using for-each-group).
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

February 13th, 2006, 07:41 AM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks for the quick reponse.
I don't wish to group the results into pages if i can avoid it, this is what i would like to do:
Code:
// Get a new result sorted correctly by date
<xsl:variable name="sorted-set">
<xsl:for-each select="portfolio/campaign">
<xsl:sort select="substring(@date,7,4)" order="descending"/>
<xsl:sort select="substring(@date,4,2)" order="descending"/>
<xsl:sort select="substring(@date,1,2)" order="descending"/>
<xsl:call-template name="campaign"/>
</xsl:for-each>
</xsl:variable>
// The loop through that result (I am using php5 to parse the xml, what would i replace the xx with)
<xsl:for-each select="xx:node-set($sorted-set)/[position() > $vFirstRecord][position() <= $pRecordsPerPage]">
<xsl:call-template name="campaign"/>
</xsl:for-each>
Is this possible?
|
|

February 13th, 2006, 09:01 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
You said in your first post that you wanted to split the results into pages, and in your second post that you didn't, so I give up.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

February 13th, 2006, 09:14 AM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Sorry about that misunderstanding.
I do want to split the results up into pages, but not like <page>...</page>, just using position() and by passing parameters to it.
The xsl is passed a $vFirstRecord (start position for results) and a $pRecordsPerPage parameter, when a user clicks on the next and back buttons the $vFirstRecord changes accordingly. For example,
$vFirstRecord = 1
$pRecordsPerPage = 18
Shows nodes 1 to 18.
The $vFirstRecord parameter will be reset to 19, and appended to the url.
(Sorry if i'm stating the obvious)
I want to sort the xml file by date, then loop through the results showing 18 at a time, but keep the sort order. At the moment it is paging correctly but not sorting correctly.
Any ideas?
|
|

February 13th, 2006, 11:14 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
You can do this in a single pass:
<xsl:for-each select="(unsorted nodes)">
<xsl:sort select="(sort key)">
<xsl:if test="position() >= $start and position() ≤ $end">
(output the value_
</xsl:if>
</xsl:for-each>
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

February 13th, 2006, 11:56 AM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks, but now I can only view the first page, when i click on the next button it returns no results.
Code:
<xsl:for-each select="portfolio/campaign">
<xsl:sort select="substring(@date,7,4)" order="descending"/>
<xsl:sort select="substring(@date,4,2)" order="descending"/>
<xsl:sort select="substring(@date,1,2)" order="descending"/>
<xsl:if test="position() > $vFirstRecord and position() <= $pRecordsPerPage">
<xsl:call-template name="campaign"/>
<xsl:call-template name="newRow" select="campaign[position() mod 6 = 0]"/>
</xsl:if>
</xsl:for-each>
The parameters are being passed to the xsl, I am able to print them out as far as the xsl:if statement.
|
|

February 13th, 2006, 12:08 PM
|
|
Registered User
|
|
Join Date: Feb 2006
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Sorry just seen my mistake. Forgot to add the records per page to start position: Here is the working code:
[code]
<xsl:for-each select="portfolio/campaign">
<xsl:sort select="substring(@date,7,4)" order="descending"/>
<xsl:sort select="substring(@date,4,2)" order="descending"/>
<xsl:sort select="substring(@date,1,2)" order="descending"/>
<xsl:if test="position() > $vFirstRecord and position() <= $vFirstRecord + $pRecordsPerPage">
<xsl:call-template name="campaign"/>
</xsl:if>
</xsl:for-each>
</code]
|
|

January 30th, 2007, 10:40 AM
|
|
Registered User
|
|
Join Date: Jan 2007
Posts: 1
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
There seems to be a bug in xsl:sort. I am using XSLT2.0. Here is the code that I am using to sort and list only 20 rows.
<xsl:for-each select="$reportRecords">
<xsl:sort select="./descendant::*[name()=$sortcol]" order="{$sortorder}" data-type="{$sortDataType}"></xsl:sort>
<xsl:if test="position() >= number($startRow) and position() <= number($endRow)">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:if>
</xsl:for-each>
"startRow" and "endRow" are being set based on the page number. The difference will always be 20.
What it does is always picks up the first 20 records from $reportRecords and sort them. That means it picks
$reportRecords[1-20] and sorts them always. The position() is not relative to sorted result, it relates to the original set of nodelist.
|
|

January 30th, 2007, 01:00 PM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
I agree with you: whether you are using XSLT 1.0 or 2.0, position() within the for-each should reflect the position in the sorted sequence, not the unsorted sequence. Raise the issue with your XSLT vendor.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|
 |