Create a Google style paging component in XSLT

I’ve noticed how most of the Sitecore blogs takes up relatively advanced topics on Sitecore, so I’ve decided to share with you some of my more simpler tricks.

This article is meant as a tutorial.  This is a small XSLT I’ve done for several projects that will display a Google style paging selector for any list. Imagine you have a list with 200 items. Displaying all items on one page can slow down your page and make it cluttered. Instead we add a paging component (like Google does it) to the top of the list, and display only 10 items from the list at a time. When clicking the pager, the same page will be called with a parameter ?page=n. The list uses the querystring to determine which elements from the list to display.

Lets begin with the component. First I create a new xsl:template called tplPaging:

<xsl:template name="tplPaging">
  <!-- Identifies the number of items in the list -->
  <xsl:param name="numberOfItems" />
  <!-- Optional parameter identifying the default selected page. Default is 1 -->
  <xsl:param name="currentPage" select="sc:qs('page','1')" />
  ... <!-- more code here -->
</xsl:template>

The template needs 2 parameters, the length of the list (total number of items), and the current page. The current page value can be taken from the querystring, and the default value is page one. So if nothing is defined, we will start with page 1.

Then I need 3 variables: Total number of pages, the start page and the end page. In this case I will only draw 5 pages before and after the current page. Google draws 10, but my lists are shorter, so I’ll stick to 5.

<!-- Calculate the maximum number of pages to show in the paging component -->
<xsl:variable name="numberOfPages" select="floor((number($numberOfItems)-1) div 10)+1"/>

<!-- Calaulate the starting position of the numbers -->
<xsl:variable name="startPage">
  <xsl:choose>
    <xsl:when test="$currentPage > 6">
      <xsl:value-of select="$currentPage - 5"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="1"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- Calculate the ending position of the numbers -->
<xsl:variable name="endPage">
  <xsl:choose>
    <xsl:when test="$numberOfPages - $currentPage > 5">
      <xsl:value-of select="$currentPage + 5"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$numberOfPages"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

Now I can recursively draw the numbers in the paging component. I’ll show you the recursive template later. First the code to call the recursive loop:

<!-- Recursively draw the paging component -->
<ul>
  <xsl:if test="$startPage > 1">
	<li>
      <a href="?page={$currentPage - 6}">Previous</a></li>
  </xsl:if>
  <xsl:call-template name="tplNumber">
    <xsl:with-param name="current" select="$currentPage"/>
    <xsl:with-param name="number" select="$startPage"/>
    <xsl:with-param name="max" select="$endPage"/>
  </xsl:call-template>
  <xsl:if test="$currentPage + 5 < $numberOfPages">
	<li>
      <a href="?page={$currentPage + 6}">Next</a></li>
</xsl:if></ul>

Notice how I do not draw the Previous and the Next unless they are needed?
The template tplNumber is called to draw the actual numbers:

<xsl:template name="tplNumber">
  <xsl:param name="current"/>
  <xsl:param name="number"/>
  <xsl:param name="max"/>

  <xsl:choose>
    <xsl:when test="$number = $current">
      <!-- Show current page without a link -->
	<li class="current">
        <xsl:value-of select="$number"/>
     </li>
    </xsl:when>
    <xsl:otherwise>
	<li>
        <a href="?page={$number}"><xsl:value-of select="$number"/></a>
     </li>
    </xsl:otherwise>
  </xsl:choose>

  <!-- Recursively call the template untill we reach the max number of pages -->
  <xsl:if test="$number < $max">
    <xsl:call-template name="tplNumber">
      <xsl:with-param name="current" select="$current"/>
      <xsl:with-param name="number" select="$number+1"/>
      <xsl:with-param name="max" select="$max"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

You can expand this function. What should the pager do if there is no items in the list? Anyway, the examle is actually very simple and shows how easy it is to do paging. And by the way – Sitecore will actually render this blindingly fast.

Reading from ITunes

Apple ITunes have a huge COM object API, from where you can control ITunes. The API are of course accessible from C# and .NET simply by adding a reference to the COM library. The ITunes library is called “iTunes 1.11 Type Library” (or whatever version of ITunes you have running).

One thing you need to know: When you create a new instance of the ITunes app, the ITunes application will load in the background. To avoid this, you can check to see if the ITunes application is running, and only if it is create the ITunes instance. This is a template class that instantiates an ITunes object only if ITunes is running.

using System;
 

namespace Pentia.ITunes
{
  internal class ITunesReader : IDisposable
  {
    /// <summary>
    /// The ITunes COM application
    /// </summary>
    private iTunesLib.iTunesAppClass _app = null;

    /// <summary>
    /// Initializes a new instance of the <see cref="ITunesReader"/> class.
    /// </summary>
    public ITunesReader()
    {
      // See if the itunes process is running.
      if (System.Diagnostics.Process.GetProcessesByName("iTunes").Count() > 0)
        _app = new iTunesLib.iTunesAppClass();
    }

    /// <summary>
    /// Gets a value indicating whether this instance is active.
    /// </summary>
    /// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
    public bool IsActive
    {
      get
      {
        return _app != null;
      }
    }

    #region IDisposable Members

    /// <summary>
    /// Performs application-defined tasks associated with freeing,
    /// releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
      if (_app != null)
      {
        // Release the com object by setting the reference counter to 0 
        Marshal.FinalReleaseComObject(_app);
      } 
    }

    #endregion
  }
}

Please notice that I use the IDisposable interface in order to release my reference to ITunes.

Now, lets see if ITunes is playing:

_app.PlayerState == iTunesLib.ITPlayerState.ITPlayerStatePlaying;

The ITunes library is not perfect. For example, _app.CurrentTrack is describing the current track playing, but you cannot see if it is playing a radio station or a song from the library. This is how I solved the radio/song issue:

if (_app.PlayerState == iTunesLib.ITPlayerState.ITPlayerStatePlaying)
{
 if (_app.CurrentStreamTitle != null)
 {
   // We are listening to a radio station
   Console.WriteLine("Radio Station name: " + _app.CurrentTrack.Name);
   Console.WriteLine("Track: " + _app.CurrentStreamTitle);
 } 
 else
 {
   // We are listening to a song
   Console.WriteLine("Track: " + _app.CurrentTrack.Name);
   Console.WriteLine("Artist: " + _app.CurrentTrack.Artist);
   Console.WriteLine("Album: " + _app.CurrentTrack.Album);
   Console.WriteLine("Length (in seconds): " + _app.CurrentTrack.Duration.ToString());
   Console.WriteLine("Position (in seconds): " _app.PlayerPosition.ToString());
 }
}

You can do much more that this. You can start/stop songs, create your own playlists and even convert your songs to new formats. Explore the API for yourself. I wish you happy ITunes’ing.

Get HTML from page

This piece of code have followed me since 2003 and I have used it several times. It simply retrieves the text from a URL and returns it as a string. The code is usefull for reading RSS feeds or getting HTML from pages. I even used the code to stress test a certain page on my website.

public string GetPage(string url, NameValueCollection headers)
{
  try
  {
    string ret = "";
    System.Net.WebRequest myRequest = System.Net.WebRequest.Create(url);
    myRequest.PreAuthenticate = true;
    myRequest.Method = "GET";
    if (headers != null)
      myRequest.Headers.Add(headers);
    System.Net.WebResponse myResponse = myRequest.GetResponse();
    try
    {
      Stream stream = myResponse.GetResponseStream();
      StreamReader streamreader = new System.IO.StreamReader(stream);
      ret = streamreader.ReadToEnd();
      return ret.Replace("\x00", "");
    }
    finally
    {
      myResponse.Close();
    }
  }
  catch (Exception ex)
  {
    throw new Exception("Could not get HTML from " + url + ": " + ex.Message, ex);
  }
}

Calling the code is very easy:

GetPage("http://www.pentia.dk", null);