Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bjarne Fyrstenborg 1284 posts 4038 karma points MVP 8x c-trib
    Dec 05, 2012 @ 00:59
    Bjarne Fyrstenborg
    0

    Get random node of the ones picked with MNTP

    Hi..

    I have some quotes listed in my content structure..

    On each page I want to pick the nodes which should appear on the current page.. but of the nodes picked with multi-node tree picker a random of the selected quotes should be displayed.

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <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.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:PS.XSLTsearch="urn:PS.XSLTsearch" 
        exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets PS.XSLTsearch ">
    
    
      <xsl:output method="xml" omit-xml-declaration="yes"/>
    
      <xsl:param name="currentPage"/>
      <xsl:variable name="boxIds" select="$currentPage/self::*[normalize-space(boxes)][1]/boxes//nodeId" />
    
      <xsl:variable name="random" select="floor(Exslt.ExsltMath:random() * count($boxIds)) + 1"/>
    
      <xsl:template match="/">
          <xsl:if test="normalize-space($boxIds)"> 
            <xsl:for-each select="$boxIds">
                <xsl:variable name="box" select="umbraco.library:GetXmlNodeById(.)" />
                <xsl:apply-templates select="$box" />
            </xsl:for-each>
          </xsl:if>
      </xsl:template>
    
      <xsl:template match="Quote">
          <xsl:variable name="qSize" select="quoteTextSize" />
          <xsl:variable name="textSize">
            <xsl:value-of select="Exslt.ExsltStrings:lowercase($qSize)"/>
          </xsl:variable>
    
          <xsl:variable name="qClass">
          <xsl:choose>
            <xsl:when test="$textSize = 'small' or $textSize = ''">
                <xsl:value-of select="'smallText'"/>
            </xsl:when>
            <xsl:when test="$textSize = 'medium'">
                <xsl:value-of select="'mediumText'"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="'largeText'"/>
            </xsl:otherwise>
          </xsl:choose>
          </xsl:variable>
    
          <section>
                <xsl:attribute name="class">
                    <xsl:text>quoteBox </xsl:text>
                    <xsl:value-of select="$qClass"/>
                </xsl:attribute>
                <p class="quoteText">
                    <xsl:if test="quoteText != ''">
                        <xsl:value-of select="concat('&quot;', umbraco.library:ReplaceLineBreaks(quoteText), '&quot;')" disable-output-escaping="yes"/>
                    </xsl:if>
                </p>
                <p class="quoteName"><xsl:value-of select="umbraco.library:ReplaceLineBreaks(quoteName)" disable-output-escaping="yes"/></p>
          </section>
    
      </xsl:template>
    
    </xsl:stylesheet>

    How can I set the random Quote node of the selected in the apply-templates?

    /Bjarne

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Dec 05, 2012 @ 08:43
    Chriztian Steinmeier
    0

    Hi Bjarne,

    Here's a way to do that:

    <xsl:template match="/">
        <!-- Pick a random box index -->
        <xsl:variable name="random" select="floor(Exslt.ExsltMath:random() * count($boxIds)) + 1"/>
    
        <!-- Process the one - this gets us into the Umbraco XML doc -->
        <xsl:apply-templates select="$boxIds[position() = $random]" />
    </xsl:template>
    
    <!-- Simple 'redirect' to the referenced node -->
    <xsl:template match="nodeId">
        <!-- id() works because we are now inside the Umbraco XML -->
        <xsl:apply-templates select="id(.)" />
    </xsl:template>
    
    <!-- Template for the Quote -->
    <xsl:template match="Quote">
        <!-- Do something -->
    </xsl:template>

     

    The difference between id() and GetXmlNodeById() is that id() will return an empty set if the picked node has been deleted (it's also a native XPath function), where GetXmlNodeById() will return an error node (or something) that you will then need to error check.

    The tricky part is that id() will only find a node inside the document that contains the current context node - a concept that's also hard to explain in Umbraco's specific environment - I tried here: https://gist.github.com/871656

    So by applying templates for the randomly selected <nodeId> element, we get "into" the Umbraco XML and from there can just use the id() function and not worry about error messages for deleted nodes.

    I know it's a completely different way of thinking, in terms of what most people are used to, but using XSLT it just makes so much more sense.

     

    /Chriztian

  • Bjarne Fyrstenborg 1284 posts 4038 karma points MVP 8x c-trib
    Dec 05, 2012 @ 13:10
    Bjarne Fyrstenborg
    0

    Hi Chriztian

    Thanks, it seems to do it :)

    I have done something similar before, but where I just get a random node of a nodeset.

    <xsl:param name="currentPage"/>
            <xsl:variable name="random" select="floor(emath:random() * count($currentPage/ancestor-or-self::root/descendant-or-self::Quote)) + 1"/>

            <xsl:template match="/">
             <xsl:apply-templates select="$currentPage/ancestor-or-self::root/descendant-or-self::Quote[$random]" />
            </xsl:template>

            <xsl:template match="Quote">
                    <div id="randquote">
                            <xsl:apply-templates select="quoteText[normalize-space()]" />
                            <xsl:apply-templates select="quoteName[normalize-space()]" />
                    </div>
            </xsl:template>
            
            <xsl:template match="quoteText">
                    <class="quoteText">
                            <xsl:value-of select="." />
                      <span class="quote_end"><xsl:text</xsl:text></span>
                    </p>
                    
            </xsl:template>
              
            <xsl:template match="quoteName">
                    <class="name">
                            <xsl:value-of select="." />
                    </p>
            </xsl:template>

     

    So what you get from the code above is a random node id and from that get the xml?

    This is the code I ended up with:

    <xsl:param name="currentPage"/>
      <xsl:variable name="boxIds" select="$currentPage/self::*[normalize-space(boxes)][1]/boxes//nodeId" />
      <!-- Replace 'article' with the wanted document -->
      <xsl:variable name="random" select="floor(Exslt.ExsltMath:random() * count($boxIds)) + 1"/>
    
      <xsl:template match="/">
          <!-- Pick a random box index -->
          <xsl:variable name="random" select="floor(Exslt.ExsltMath:random() * count($boxIds)) + 1"/>
    
          <!-- Process the one - this gets us into the Umbraco XML doc -->
          <xsl:apply-templates select="$boxIds[position() = $random]" />
      </xsl:template>
    
      <!-- Simple 'redirect' to the referenced node -->
      <xsl:template match="nodeId">
            <!-- id() works because we are now inside the Umbraco XML -->
            <xsl:apply-templates select="id(.)" />
      </xsl:template>
    
      <xsl:template match="Quote">
          <xsl:variable name="qSize" select="quoteTextSize" />
          <xsl:variable name="textSize">
            <xsl:value-of select="Exslt.ExsltStrings:lowercase($qSize)"/>
          </xsl:variable>
    
          <xsl:variable name="qClass">
          <xsl:choose>
            <xsl:when test="$textSize = 'small' or $textSize = ''">
                <xsl:value-of select="'smallText'"/>
            </xsl:when>
            <xsl:when test="$textSize = 'medium'">
                <xsl:value-of select="'mediumText'"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="'largeText'"/>
            </xsl:otherwise>
          </xsl:choose>
          </xsl:variable>
    
          <section>
                <xsl:attribute name="class">
                    <xsl:text>quoteBox </xsl:text>
                    <xsl:value-of select="$qClass"/>
                </xsl:attribute>
                <p class="quoteText">
                    <xsl:if test="quoteText != ''">
                        <xsl:value-of select="concat('&quot;', umbraco.library:ReplaceLineBreaks(quoteText), '&quot;')" disable-output-escaping="yes"/>
                    </xsl:if>
                </p>
                <p class="quoteName"><xsl:value-of select="umbraco.library:ReplaceLineBreaks(quoteName)" disable-output-escaping="yes"/></p>
          </section>
    
      </xsl:template>

    /Bjarne

Please Sign in or register to post replies

Write your reply to:

Draft