Reputation: 1915
I have a question about some sort af random function in XSLT.
I have an XML-file that very simplified look similar to this:
<node id="1198">
<node id="1201">
<data alias="name">Flemming</data>
<data alias="picture">1200</data>
</node>
<node id="1207">
<data alias="name">John</data>
<data alias="picture">1205</data>
</node>
<node id="1208">
<data alias="name">Michael</data>
<data alias="picture">1206</data>
</node>
</node>
I would like to have some XSLT, that ramdomly took one of the nodes id's and put it into a variable called "choosenNode". Like this, if the node with the ID of 1207 was the selected one:
<xsl:variable name="choosenNode" value="1207" />
How can i do this? Is there a random-function in XSLT? By the way, I would like the variable to be refreshed on every page where the XSLT is included.
And I work in Umbraco CMS, if that helps you guys.
Thanks, -Kim
Upvotes: 7
Views: 5382
Reputation: 1674
The following assumes the XSLT processor supports EXSLT extensions (e.g., xsltproc).
This will return the content of the randomly selected "node" (it must be a child of a "node", i.e. a "node/node" element).
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://exslt.org/math"
extension-element-prefixes="math" >
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="node">
<xsl:variable name='selected'>
<xsl:value-of select="ceiling(math:random() * count(node))"/>
</xsl:variable>
<xsl:copy-of select="node[position() = $selected]"/>
</xsl:template>
</xsl:stylesheet>
This might be a useful snippet to process the content of the selected node:
<xsl:variable name="randomNode" select="node[position() = $selectNode]"/>
<id><xsl:value-of select="$randomNode/@id"/></id>
<name><xsl:value-of select="$randomNode/data[@alias='name']"/></name>
<picture><xsl:value-of select="$randomNode/data[@alias='picture']"/></picture>
Note that the above does not return the xslt definition of the variable, it uses that variable to copy the selected node.
To set the 'value' attribute of an xsl:variable element, try an attribute template like:
<xsl:variable name='chosenNode' value='{node[position() = $selected]/@id}'/>
Upvotes: 0
Reputation: 1674
This solution works in a shell script that uses xsltproc and text utilities.
RandomElement=$(xsltproc style.xsl file.xml | tr ' ' '\n' | sort -uR | head -n 1)
It's assumed that the style.xsl
file will select the required element set and return it's values, one per line in the output text file. The tr
command should put each element onto a separate line. The sort -uR
should produce a unique, random list of the elements selected by the style.xsl
style sheet commands. The head -n 1
then pulls out the first line of the unique, random list.
Upvotes: 0
Reputation: 4410
In Umbraco you can do something like this:
<?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:Exslt.ExsltMath="urn:Exslt.ExsltMath"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltMath">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<!-- This should probably be a macro parameter so you can use this elsewhere-->
<xsl:variable name="parentNode" select="1048"/>
<xsl:template match="/">
<xsl:variable name="numberOfNodes" select="count(umbraco.library:GetXmlNodeById($parentNode)/node)"/>
<xsl:variable name="randomPosition" select="floor(Exslt.ExsltMath:random() * $numberOfNodes) + 1"/>
<xsl:variable name="randomNode" select="umbraco.library:GetXmlNodeById($parentNode)/node [position() = $randomPosition]"/>
<!--
You now have the node in the $randomNode variable
If you just want the id then you can do an XPath query on the variable
or you can modify the XPath above to get the property you are after rather than
the whole node
-->
<xsl:value-of select="$randomNode/@nodeName" />
</xsl:template>
</xsl:stylesheet>
Hope this helps.
Tim
Upvotes: 7
Reputation: 26682
All you need is a random number generator. There is none in XSLT thus the random number must be provided by something outside of XSLT. You will need to call a method from an external library to do this and the implemention of this library will depend on if you're on Windows (.NET or WIN32) or Linux and the XSLT processor. XSLT can do math but it lacks a lot of date/time related functions which happens to include a random number generator.
However, XSLT does have a XPath function called generate-id() which will generate an unique ID. If you could transform this to a nuimber somehow, it might be used to create a random number, although it would be predictable and some numbers might occur more often than others. I wouldn't use it.
If you use MSXSL to process your stylesheet then you can include JavaScript to generate random numbers within the stylesheet. (Or C# script when using .NET.)
Getting the node itself is easy, once you know the number of child nodes. Just ask for the node at the random position. Something like /node/node[5] would return the 5th node.
Upvotes: 0
Reputation: 17817
Getting random number in xslt is not an easy task.
There's something that can do it but you probably has to provide seed for random generator http://fxsl.sourceforge.net/articles/Random/Casting%20the%20Dice%20with%20FXSL-htm.htm
Maybe the processor you are using to do xsl transformation has ability to extend xsl expressions with outside functions. In that case maybe you can use outside random function.
Upvotes: 0