Skip to content

Getting n random items

September 7, 2008

The project I’m working on involves showing various case studies. On my case study index page, I wanted to be able to show a selection of random case studies (say, up to four).

I can select all the relevant case studies using:
<xsl:variable name=”featuredall” select=”$sc_item//item[@template=’case study’ and sc:fld(‘featured’,.)!=”]” />

However, selecting a set of random items from this set isn’t as easy as it sounds. Using sc:random won’t work, because there’s a chance that the same case study will be used more than once.

After much head-scratching, I wrote an XSL Extension which returns a simple nodeset of random integers. This allows me to iterate through that nodeset, referring to the relevant position in my set of case study items…

The XSL Extension:

using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Collections.Generic;
using System.Text;

namespace Flag08v2.classes
{
public class RandomTest
{

public XPathNodeIterator RandomSequence2(int n)
{

Random randomGen = new Random();

List<int> numbers = new List<int>(n);
for (int x = 1; x<=n; x++)
numbers.Add(x);

List<int> randNumbers = new List<int>(n);
for (int x = 0; x<n; x++)
{
int rn = randomGen.Next(numbers.Count);
int rnVal = numbers[rn];

randNumbers.Add(rnVal);
numbers.RemoveAt(rn);
}

Sitecore.Xml.Packet packet = new Sitecore.Xml.Packet("values", new string[0]);
foreach (int i in randNumbers)
packet.AddElement("value", i.ToString(), new string[0]);

XPathNavigator navigator = packet.XmlDocument.CreateNavigator();
navigator.MoveToRoot();
navigator.MoveToFirstChild();

return navigator.SelectChildren(XPathNodeType.Element);
}
}
}

Then, add the reference to the XSL Extension in the <xsl:stylesheet> declaration:


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sc="http://www.sitecore.net/sc"
xmlns:dot="http://www.sitecore.net/dot"
xmlns:mt="http://www.flag.co.uk/random"
exclude-result-prefixes="dot sc"
>

And to iterate through the case studies (“maxfeatured” is the maximum number of case studies to show – I set this using a field elsewhere):


...

<xsl:variable name="featuredall" select="$sc_item//item[@template='case study' and sc:fld('featured',.)!='']" />
<xsl:for-each select="mt:RandomSequence2(count($featuredall))">
<xsl:if test="position() <= $maxfeatured or $maxfeatured = 0">
<xsl:variable name="thisNum" select="text()" />
<xsl:variable name="thisItm" select="$featuredall[position() = $thisNum]" />

Item <xsl:value-of select="text()"/> = <xsl:value-of select="sc:fld('title',$thisItm)"/>

</xsl:if>
</xsl:for-each>

Hope that makes sense!

Mike

From → sitecore, xsl

Leave a Comment

Leave a comment