 |
| 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
|
|
|
|

June 3rd, 2007, 11:20 PM
|
|
Registered User
|
|
Join Date: Jun 2007
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Grouping and Pagination
Hello,
I'm new to XSLT and I would like to ask if it is possible to do pagination after grouping of records?
I'm using XSLT 1.0. I use a c# program to get records from a DB and return a xml file contains records of articles. All the formattings will be done by the XSLT. The records need to be grouped and sorted according to their authors or categories, etc. Each page shows 10 records. The following is the output format that I want to have.
(Page 1)
Author A
Article 3
Article 7
Article 18
Article 20
Author B
Article 1
Article 30
Article 40
Article 41
Author C
Article 5
Article 8
Next Page >>
----------------------------------------------------
(Page 2)
Author C
Article 21
Article 26
Author D
Article 25
Article 60
<< Previous Page
I succeeded in grouping of results and I know how to do pagination when there is no Grouping. however I do not have idea on how to combine grouping and pagination.
Thanks in advance.
|
|

June 4th, 2007, 01:40 AM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
|
|
Well it maybe better to group and paginate in the underlying query but if you want to do it in the XSLT stage then you need to first group. If you're using XSLT 1.0 then you need to look at Muenchian grouping, there's a link on the first post in this forum, if using version 2.0 then you can use xsl:for-each-group.
The pagination will act on the grouped records and will need two parameters in the stylesheet, one that holds the number of records per page and the other which page you wish to display. You then use these two values to only show the records that are in the range calculated by:
First record = ($recordsPerPage * ($pageNumber - 1)) + 1
Last record = ($recordsPerPage * $pageNumber)
--
Joe ( Microsoft MVP - XML)
|
|

June 4th, 2007, 03:25 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
I think this kind of thing is best done in a multi-pass transformation (sometimes called a pipeline). First do the grouping, then apply pagination to the result. You can do this in two separate stylesheets, or you can do it in a single stylesheet provided (in 1.0) that you have the xx:node-set() extension to make the output of the first pass accessible for processing by the second. Separate stylesheets makes the code more reusable and modular, but can be a bit more difficult to deploy depending on the environment you are running in.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

June 4th, 2007, 04:42 AM
|
|
Registered User
|
|
Join Date: Jun 2007
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thank you for the replies.
The environment for me to run this program is difficult to have separate stylesheets and I wish to do it in a single stylesheet.
I have read about Muenchian grouping and able to group the records by Author/Category.
Here is part of the codes in the XSLT regarding the grouping of articles. (I hope this is enough, if not, I'll show more next time.)
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:key name="rows" match="Record" use="author" />
<xsl:template match="ArticleRecords">
<xsl:apply-templates select="Record[generate-id(.) = generate-id(key('rows', author)[1])]">
<xsl:sort select="author"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Record">
<xsl:for-each select="key('rows', author)">
<xsl:value-of select="title"/>
<xsl:value-of select="author"/>
</xsl:for-each>
</xsl:template>
The above codes is for the grouping of author and it works.
I know how to do pagination if there's no grouping. However I don't know how to combine them.
Michael said that it can be done with xx:node-set(), where should I put this inside my code?
Thanks in advance.
|
|

June 4th, 2007, 04:53 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
The general pattern for doing a multi-phase transformation within a single stylesheet is:
<xsl:template match="/">
<xsl:variable name="r1">
<xsl:apply-templates mode="phase1"/>
</xsl:variable>
<xsl:variable name="r2">
<xsl:apply-templates select="xx:node-set($r1)" mode="phase2"/>
</xsl:variable>
<xsl:apply-templates select="xx:node-set($r2)" mode="phase3"/>
</xsl:template>
Here xx:node-set() represents whatever node-set() extension function is available in your chosen processor.
Of course one of the phases can be done in the default mode, or they can all be done in the default mode if none of the template rules conflict.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

June 4th, 2007, 05:26 AM
|
|
Registered User
|
|
Join Date: Jun 2007
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Does this means that I can:
1. do grouping first,
2. store the grouped records as r1, and,
3. group every 10 records in r1?
For example:
<xsl:for-each select="exsl:node-set($r1)/*[position() mod 10 = 1]">
<xsl:copy-of select=".|following-sibling::*[position() < 10]"/>
</xsl:for-each>
Is this correct?
|
|

June 4th, 2007, 07:22 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
Yes, that looks about right.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

June 4th, 2007, 11:04 PM
|
|
Registered User
|
|
Join Date: Jun 2007
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
I still cannot figure it out, it still shows all records instead of 10 records...
The xml source file:
Code:
<ArticleRecords>
<Record>
<ID>9</ID>
<TITLE>Some Article Title</TITLE>
<AUTHOR>Author A</AUTHOR>
<DESCRIPTION>Some Article Description</DESCRIPTION>
<PUBLISHDATE>2007-02-15</PUBLISHDATE>
</Record>
<Record>
<ID>17</ID>
<TITLE>Another Article Title</TITLE>
<AUTHOR>Author B</AUTHOR>
<DESCRIPTION>Another Article Description</DESCRIPTION>
<PUBLISHDATE>2007-02-15</WRITE>
</Record>
</ArticleRecords>
The xslt part regarding article records:
Code:
<xsl:template match="ArticleRecords">
<xsl:apply-templates select="Record[generate-id(.) = generate-id(key('rows', author)[1])]">
<xsl:sort select="author"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Record">
<b><xsl:value-of select="author"/></b>
<xsl:variable name="groupedrecords">
<xsl:for-each select="key('rows', author)">
<xsl:call-template name="showrecord" />
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="exsl:node-set($groupedrecords)/*[position() mod 10 = 1]">
<xsl:copy-of select=".|following-sibling::*[position() < 10]"/>
</xsl:for-each>
</xsl:template>
Thanks in advance.
|
|

June 5th, 2007, 02:47 AM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
Since "author" is upper-case in your XML and lower-case in your stylesheet, I'm surprised that this is displaying anything at all.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

June 5th, 2007, 03:49 AM
|
|
Registered User
|
|
Join Date: Jun 2007
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Actually that was the code of my last trial...
I have tried both uppercase and lowercase.
The problem seems to be at here:
Code:
<xsl:for-each select="exsl:node-set($groupedset)/*[position() mod 10 = 1]">
<xsl:copy-of select=".|following-sibling::*[position() < 10]"/>
</xsl:for-each>
I'm trying to figure out what the problem is...
|
|
 |