This is in response to an
earlier post detailing my troubles. This functionality follows on from another author's random image XSLT but I decided I wanted the images to be not only random but
unique and also to be able to get more than 1 image out. I had no idea the can of worms I was about to open up :) Here is my solution.
First, create a new XSLT file called RandomImages. Leave the box checked to create the associated macro. Here is the XSLT:
Code:<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [<!ENTITY nbsp " ">]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:aqua="urn:schemas-my-org:aqua"
xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings"
xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath"
exclude-result-prefixes="msxml Exslt.ExsltMath Exslt.ExsltStrings aqua umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:variable name="StartNode" select="/macro/StartNode/node/@id" />
<xsl:variable name="NumberOfImages" select="/macro/NumberOfImages" />
<xsl:variable name="parent" select="umbraco.library:GetMedia($StartNode, 'false')" />
<xsl:variable name="randomNumbers" select="aqua:random($NumberOfImages, count($parent/node))"/>
<xsl:template match="/">
<xsl:for-each select="$randomNumbers/numbers/number">
<xsl:variable name="randomPosition" select="."/>
<xsl:for-each select="$parent/node">
<xsl:variable name="parentPosition" select="position()"/>
<xsl:if test="$parentPosition = $randomPosition">
<xsl:if test="./data [@alias = 'umbracoExtension'] = 'gif' or ./data [@alias = 'umbracoExtension'] = 'jpg' or ./data [@alias = 'umbracoExtension'] = 'jpeg' or ./data [@alias = 'umbracoExtension'] = 'png'">
<div class="Random{$currentPage/@nodeName}Image">
<xsl:element name="img">
<xsl:attribute name="src"><xsl:value-of select="./data [@alias = 'umbracoFile']"/></xsl:attribute>
<xsl:attribute name="alt"><xsl:value-of select="@nodeName"/></xsl:attribute>
<xsl:attribute name="width"><xsl:value-of select="./data [@alias = 'umbracoWidth']"/></xsl:attribute>
<xsl:attribute name="height"><xsl:value-of select="./data [@alias = 'umbracoHeight']"/></xsl:attribute>
</xsl:element>
</div>
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<msxml:script language="CSharp" implements-prefix="aqua">
<msxml:using namespace="System.Collections.Generic" />
<msxml:using namespace="System.IO" />
public XPathNodeIterator random(int numMin, int numMax)
{
int i;
Random random = new Random();
List<int> numbersList = new List<int>();
for (i = 1; i < numMax + 1; i++)
{
numbersList.Add(i);
}
int numRange = numMax - numMin;
for (i = 0; i < numRange; i++)
{
int index = random.Next(0, numbersList.Count);
numbersList.RemoveAt(index);
}
StringBuilder stringBuilder = new StringBuilder("<numbers>");
foreach (int item in numbersList)
{
stringBuilder.Append("<number>");
stringBuilder.Append(item.ToString());
stringBuilder.Append("</number>");
}
stringBuilder.Append("</numbers>");
StringReader stringReader = new StringReader(stringBuilder.ToString());
XPathDocument xPathDocument = new XPathDocument(stringReader );
XPathNavigator xPathNavigator = xPathDocument.CreateNavigator();
XPathExpression xPathExpression = xPathNavigator.Compile("/");
XPathNodeIterator xPathNodeIterator = xPathNavigator.Select(xPathExpression);
return xPathNodeIterator;
}
</msxml:script>
</xsl:stylesheet>
NB: You'll need to check the checkbox to disable error checking to save the file.
Got to the new macro and add two parameters:
Code:Alias: StartNode
Name: Start node
Type: mediaCurrent
Alias: NumberOfImages
Name: Number of images
Type: number
In the media section, create a folder to hold your images.
In a template you can then insert the macro. Select the appropriate media folder and tell the macro how many images you want to display.
In this example, images will display vertically. They are wrapped in a div. You can always change this. Hey, you could add another macro parameter for multiple presentations and use that to select a different template even.
I found implementing the above very frustrating (my lack of knowledge shone) and almost gave up. However, I'm really glad I stayed with it. Not only do I now know really well how to use script in XSLT, I found out how to put assemblies in and also how to manipulate XML and pass it back to my XSLT - all very worthwhile knowing.
There's very probably a
much better way of doing this (shhh!) but it works for me and I'm happy. If I need to change it in the future, I can go direct to this one file and make my changes.
I've pasted the file in AS IS. It's working on my site and I hope you find this useful.
Richard
2 * 3 * 3 * 37 : The prime factorisation of The Beast.