ParagraphSetup with random paragraph display

ParagraphSetup template in Dynamicweb is a great option to use, if you wanna make some custom paragraph setup or if you are working on making some sort of jQuery slide show effect with all your paragraphs, but sometimes you might only need to show one paragraph at the time in a random order. That option could be needed when creating a banner setup for your website.

The xslt nippet that I’m about to show you, can be made in many ways, and I will just show you one of them, that I personally prefer. I like to make things as dynamic as possible and with few hard-coded-static options as possible, in case I wanna to use the same code somewhere else.

If you ask me then, the best way to show a random paragraph on a website is only to output that single paragraph. That way you won’t need to hide ekes. 100 paragraphs and then only show one of them, using some sort of JavaScripts or CSS3. So I’ll show you how you can display a random paragraph without outputting all your paragraphs to your page.

XML

Before we can start writing our XSLT snippet we’ll need to know how our XML output looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<Template>
<ParagraphHeader></ParagraphHeader>
<ParagraphText></ParagraphText>
<TemplateMedia1></TemplateMedia1>
<TemplateMedia1Clean></TemplateMedia1Clean>
<TemplateLink1></TemplateLink1>
<TemplateMedia2></TemplateMedia2>
<TemplateMedia2Clean></TemplateMedia2Clean>
<TemplateLink2></TemplateLink2>
<TemplateMedia3></TemplateMedia3>
<TemplateMedia3Clean></TemplateMedia3Clean>
<TemplateLink3></TemplateLink3>
<TemplateMedia4></TemplateMedia4>
<TemplateMedia4Clean></TemplateMedia4Clean>
<TemplateLink4></TemplateLink4>
<TemplateMedia5></TemplateMedia5>
<TemplateMedia5Clean></TemplateMedia5Clean>
<TemplateLink5></TemplateLink5>
<TemplateParagraphHeader1></TemplateParagraphHeader1>
<TemplateParagraph1></TemplateParagraphColumn1>
<TemplateParagraphHeader2></TemplateParagraphHeader2>
<TemplateParagraph2></TemplateParagraph2>
</Template>

As you can see it is one messy XML dump, and honestly I don’t understand why it is like that, but if you want, then you can read about my thought on this issue in another blog post that I wrote “Dynamicweb’s XML for ParagraphSetup and how I would change it

So our paragraph templates are hidden in between all kind of ParagraphSetup nodes, and since they don’t have same node name we’ll have to make a dynamic selection that is only selecting nodes with a node name that contains word “TemplateParagraph”. But if we just do that, we’ll have a problem since it will also select following node: “TemplateParagraphHeader” meaning we’ll have to make a dynamic check for that as well.

XSLT template

The way I did this was to select all nodes that contains word “TemplateParagraph” and have a number right after “TemplateParagraph”, meaning everything that contains word “TemplateParagraph” but doesn’t follow up with a number won’t be selected. Now lets have a look at some XSLT.

1
2
3
4
5
<xsl:template match="*">
<xsl:apply-templates select="child::*">
<xsl:sort select="string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN'" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:template>

So we match all nodes and then apply a templates with all child nodes. As you can see I’m also sending a <xsl:sort> that will gives us the right positions of our nodes further down. If we don’t send the <xsl:sort> then our nodes won’t come in the right order and our position() call will have some gabs, showing node position like : 1,12,20,21,22,25… After applying a template call we’ll have to create a template that will filter our nodes.

1
2
3
4
5
6
7
<xsl:template match="*/*
[descendant-or-self::*
[contains(name(),'TemplateParagraph')]
[string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN']
]">
<em> <!--  Layout  --></em>
</xsl:template>

Now lets have a look at this selection. We are selecting a descendant nodes that contains “TemplateParagraph”. Then we use substring-after to select all characters after “TemplateParagraph” and check if that is a number. If our node have a node name that contains “TemplateParagraph” and follows up with a number, then we will have a hit. So far our XSLT snippet is dynamic and it doesn’t matter how many paragraphs we have under our ParagraphSetup. What we now need is some kind of function that can provide us a random number, which we can use to select a node based on its position.

Random number

To create a random number, I will be using JavaScript namespace in our XSLT document. So we’ll first need to apply the namespace to our document by adding the call in to our XSLT <xsl:stylesheet> definition.

1
2
3
4
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:random="http://www.microsoft.com/msxsl"
exclude-result-prefixes="msxml random">

Now that we have access to our namespace we’ll be able to create our function.

1
2
3
4
5
6
7
<msxml:script implements-prefix="random">
function range(min, max)
{
var dist = max - min + 1;
return Math.floor(Math.random() * dist + min);
}
</msxml:script>

This function can now be used in our xslt templates,simply by calling it like this: select=”random:range(1, 10)”, and you will get a random number from 1 to 10.  But I want to make this call dynamic so that I don’t have to edit my XSLT snippet each and every time I add or delete a paragraph on my page. To make my total number of paragraphs dynamic I’ll simply count how many nodes I have in my XML by using count() in XSLT.

Counting all nodes

1
2
3
4
5
count(*/*
[descendant-or-self::*
[contains(name(),'TemplateParagraph')]
[string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN']
])

As you can see my counter selection is the same one as I used for my template match. Now all I need is to save this counter as a variable and to create another variable that will provide med a random number based on my count().

1
2
3
<xsl:variable name="countParagraphs" select="count(*/*[descendant-or-self::*[contains(name(),'TemplateParagraph')][string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN']])" />
 
<xsl:variable name="randomNumber" select="random:range(1, $countParagraphs - 1)" />

Final wrap

Now lets just wrap this up into a nice xslt snippet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:random="http://www.microsoft.com/msxsl"
exclude-result-prefixes="msxml random">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"  encoding="utf-8" />
 
<msxml:script implements-prefix="random">
function range(min, max)
{
var dist = max - min + 1;
return Math.floor(Math.random() * dist + min);
}
</msxml:script>
 
<xsl:variable name="countParagraphs" select="count(*/*[descendant-or-self::*[contains(name(),'TemplateParagraph')][string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN']])" />
<xsl:variable name="randomNumber" select="random:range(1, $countParagraphs - 1)" />
 
<xsl:template match="*">
<xsl:apply-templates select="child::*">
<xsl:sort select="string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN'" data-type="number" order="descending"/>
</xsl:apply-templates>
</xsl:template>
 
<xsl:template match="*/*[descendant-or-self::*[contains(name(),'TemplateParagraph')][string(number(substring-after(name(),'TemplateParagraph'))) != 'NaN']]">
<xsl:if test="position() = $randomNumber">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:if>
</xsl:template>
</xsl:stylesheet>

By doing it this way, you will be able to use this XSLT snippet for all your web-solutions without changing XSLT.

You can download this XSLT snippet here.

Now this was my way of doing this. If you have somme suggestions or improvements, then feel free to contact me through this comment form or find me on twitter :)

Tags: , , , , , , ,

One Response to “ParagraphSetup with random paragraph display”

  1. Adelie August 11, 2011 at 06:10 #

    Well done article that. I\’ll make sure to use it wisley.

Leave a Reply

Get Adobe Flash playerPlugin by wpburn.com wordpress themes