Search

Is there a way to generate a random number in my xslt code? I've found this link but I'm not sure if the php parser will include the math extension.

Math Extension

libXSLT supports math:random(): http://exslt.org/math/functions/random/math.random.html. Just initialize your stylesheet with the following:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:math="http://exslt.org/math"
                extension-element-prefixes="math">

then use the method similar to

<xsl:value-of select="math:random()" />

The only downside to math:random() is that it will only produce a number between 0 and 1. But you're all smart monkeys, I'm sure you can multiply it by 100 or some nonsense.

Isn't that how most random number generators work? How is it a downside?

Thank you guys. This is great. I'm implementing this jQuery and CSS3 gallery

Bumping this old thread instead of starting a new one,

Is there any way to specify a range of numbers? Like if i'd want 1, 2 or 3 as a result?

Is there any way to specify a range of numbers? Like if i'd want 1, 2 or 3 as a result?

Not with math:random(), it only returns a random number from 0 to 1. A simple custom event is your best bet, something like: <?php

require_once(TOOLKIT . '/class.event.php');

Class eventrandom_number extends Event {        

public $dsParamROOTELEMENT = 'random-number';

    public static function about() {
        return array(
            'name' => 'Random Number',
            'author' => array(
                'name' => 'Your Name',
                'website' => 'Your Website',
                'email' => 'Your Email'),
            'version' => 'Symphony 2.2.5',
            'release-date' => '2012-03-08'
        );
    }

    public function load() {    
        return $this->__trigger();
    }

    public static function documentation() {
        return new XMLElement('p', 'Chooses a random number.');
    }

    protected function __trigger() {        
        $result = new XMLElement($this->dsParamROOTELEMENT);
        $result->setAttribute('number', rand(5,20));

        return $result;
    }       
}

?>

Change the range for rand() to what you want. Put it in your events folder and name it event.random_number.php.

Not easily. But you you just want 1, 2 or 3, and the random number is between 0 and 1, you can test the random number. If it's less than 0.3333... then return 1, less than 0.6666... return 2, or above return 3. Change the fraction depending on the range. You could write this as a choose/when statement.

Creative Nick!

Very easily.

<xsl:value-of select="floor(math:random()*3) + 1"/>

math:random()*3 generates a random number between 0 and 3, floor() rounds down to the next integer (0,1,2,3) and +1 offsets the whole set to (1,2,3,4).

But since the probability of math:random() picking 1.0 approaches zero the whole set shrinks to (1,2,3).

@phoque if you can't come back with an elegant algorithm in XSLT to solve this, you should declare your life a failure.

Updated my post. :-D

I hope I'm correct though... The implementors page is missing the important info about if 1.0 is actually never picked.

It does work mathematically but it comes down to the precision of the algorithm.

Bravo.

Nice @phoque, I'm going back to my corner now.

Oh, internally libxslt is using

rand() / RAND_MAX;

wich divides the returnvalue of rand() (a big integer) by its maximum possible value (depends on your system but for example 2147483647 = 231-1 on most Linux systems). This means that by a chance of 1 / 231-1 the above code will generate a random number outside the allowed range.

The fix is easy though: Modulo it by the allowed maximum number

<xsl:value-of select="(floor(math:random()*3) + 1) mod 4"/>

It only skews the distribution a bit (getting 1 is now 1 / 231-1 more likely) but solves the range issue.

Thanks four your input!

Doing a switch for math:rand() crossed my mind but it felt somewhat wild..

Phoques technique worked great, so i'm saving my event virginity a little bit more :)

@phoque: That is brilliant.

Modulo it by the allowed maximum number

With mod 4 you can still get 0 as result when the first operand is 4 (4 mod 4 = 0), thus shifting the problem from an edge number to another one.

Solution:

(floor(math:random()*3) mod 3) + 1

In this case math:random()*3 ranges from 0 to 3, with 3 being almost unlikely: the trick is to strip it out of the allowed values and then shift the result set ({0, 1, 2}) by one position to the right. This is done respectively by mod 3 and + 1.

Hah, you're right. Obviously the modulo has to be done before adding the offset.

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details