When displaying large sets of data, it is sometimes necessary to split data into pages. In this article, I will show how to create a number-based paging by using the XSL Transformation style sheet. For this example, I will take data from the Northwind database in XML format. Below is an excerpt from the data file.
<QuantityPerUnit>10 boxes x 20 bags</QuantityPerUnit>
The root element is
<Northwind> and the details are stored within the number of
Creating number-based paging
The page buttons are created as links with parameters where page numbers are passed as a part of the URL, i.e. default.aspx?page=5. One way to create such links in code is described here. But the goal of the current article is to create those links using pure XSL transformation. The transformation is applied within the
System.Web.UI.WebControls.Xml control, which is created in the default.aspx as:
<asp:Xml id="Xml1" runat="server"
The XML source is loaded from the northwind_products.xml, and the XSL Transformation style sheet is loaded from the default.xslt. Before we proceed to the transformation style sheet, I need to point out the following code in the
Page_Load handler. This code takes the
?page= parameter, creates
XsltArgumentList and passes
CurrentPage parameter to the transformation.
double CurrentPage = 1D;
if(Request.Params["page"] != null)
CurrentPage = Double.Parse(Request.Params["page"]);
XsltArgumentList xal = new XsltArgumentList();
xal.AddParam("CurrentPage", String.Empty, CurrentPage);
Xml1.TransformArgumentList = xal;
CurrentPage parameter is required to display the correct page of data and to create the appropriate links to other pages. Other optional parameters of the transformation style sheet are
PageSize is the number of items displayed per page.
MaxPages defines the maximum number of page links.
The button for a current page is not displayed as a link. For example, if the
MaxPages=5, then we will get the following result: "First ...      ... Last", where "" is a button without a link. The XSL template, which renders the buttons is provided below:
<xsl:variable name="TotalItems" select="count(Products)" />
<xsl:variable name="Pages" select="ceiling($TotalItems div $PageSize)" />
<xsl:for-each select="Products[((position()-1) mod $PageSize = 0)]">
<xsl:when test="(position() > ($CurrentPage - ceiling($MaxPages div 2)) or
position() > (last() - $MaxPages)) and
((position() < $CurrentPage + $MaxPages div 2) or
(position() < 1 + $MaxPages))">
[ <xsl:value-of select="position()"/> ]
The interesting part of this code is where the appropriate nodes are selected. The first step is to select one node of each page - the related XPath expression is
Products[((position()-1) mod $PageSize = 0)]. The resulting set will contain as many elements as there are pages. The second step is to pick only
$MaxPages of them, which surround the
$CurrentPage. Finally, the result is rendered using the
position() statement. To reduce the size of this example, I have excluded part of the code which creates links, but you can get the idea about how it is done from the
<xsl:value-of select="position()"/> statement.
Filtering the data according to page number
Template, which displays the table is rather simple:
<xsl:when test="(position() >= 1 + ($CurrentPage - 1) * $PageSize) and
(position() < (1 + $CurrentPage * $PageSize))">
<td align="center"><xsl:value-of select="UnitsInStock"/></td>
The XPath expression which selects data of the appropriate page is highlighted in bold. Note that product name is stored as an attribute, which means that we will use
@ProductName statement to select it.
Points of Interest
No doubt that there exists a simpler way of creating page buttons, consider
DataGrid for example. But think of portability. In this article, I have used C# only to pass an argument to XSLT parser, but XSLT parsers exist in various programming languages and platforms. Hopefully, my code will be useful to those, who are concerned about compatibility and portability. Also it is possible to create a letter-based paging with XSLT. If anyone has a practical need for it, please drop me a line. Thank you for your interest and remember that your opinions are highly appreciated.