Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating Page Link Buttons with XSLT

0.00/5 (No votes)
4 Jan 2004 2  
Shows how to split an XML file into pages and render page links using XSL Transformation style sheet

Sample image

Introduction

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.

<Northwind>
    <Products ProductName="Chai">
        <ProductID>1</ProductID>
        <SupplierID>1</SupplierID>
        <CategoryID>1</CategoryID>
        <QuantityPerUnit>10 boxes x 20 bags</QuantityPerUnit>
        <UnitPrice>18.0000</UnitPrice>
        <UnitsInStock>39</UnitsInStock>
        <UnitsOnOrder>0</UnitsOnOrder>
        <ReorderLevel>10</ReorderLevel>
        <Discontinued>false</Discontinued>
    </Products> 
</Northwind>

The root element is <Northwind> and the details are stored within the number of <Products>.

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" 

DocumentSource="northwind_products.xml" 

TransformSource="default.xslt"></asp:Xml>

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;

The 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 and MaxPages. 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 CurrentPage=50 and MaxPages=5, then we will get the following result: "First ... [48] [49] [50] [51] [52] ... Last", where "[50]" is a button without a link. The XSL template, which renders the buttons is provided below:

<!-- displays page buttons -->
<xsl:template name="Pages">
<xsl:variable name="TotalItems" select="count(Products)" />
<xsl:variable name="Pages" select="ceiling($TotalItems div $PageSize)" />

<!-- select first element of each page -->
<xsl:for-each select="Products[((position()-1) mod $PageSize = 0)]">
    <!-- display the appropriate portion of page links -->
    <xsl:choose>
        <!-- the expression below selects only MaxPages number of pages -->
        <xsl:when test="(position() > ($CurrentPage - ceiling($MaxPages div 2)) or 
        position() > (last() - $MaxPages)) and 
        ((position() < $CurrentPage + $MaxPages div 2) or 
        (position() < 1 + $MaxPages))">

        <!-- render non-link page button for CurrentPage -->
        <xsl:if test="position()=$CurrentPage">
        [ <xsl:value-of select="position()"/> ]
        </xsl:if>

        <!-- skipped code which creates links -->

        </xsl:choose>
</xsl:for-each>
</xsl:template>

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:template match="Products">
<xsl:choose>
    <xsl:when test="(position() >= 1 + ($CurrentPage - 1) * $PageSize) and 
    (position() < (1 + $CurrentPage * $PageSize))">

    <!-- display table rows here -->
    <tr>
    <td><xsl:value-of select="position()"/></td>
    <td><xsl:value-of select="@ProductName"/></td>
    <td><xsl:value-of select="format-number(UnitPrice,'$#.00')"/></td>
    <td align="center"><xsl:value-of select="UnitsInStock"/></td>
    </tr>

</xsl:when>
</xsl:choose>
</xsl:template>

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.

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here