Copied to clipboard

Flag this post as spam?

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


  • Garrett Fisher 341 posts 496 karma points
    Nov 10, 2009 @ 19:27
    Garrett Fisher
    0

    Alternating Between Two Different Lists

    Hi,

    I have a challenge in front of me.  I need to get the latest (by Date) five children of one node, and the latest five children of another node, and have the macro display them Alternately, as below:

    1-a

    2-a

    1-b

    2-b

    etc.

    I have a Newsroom, which has several sections-- two of which are News and Press Releases.  I want to choose these two nodes, then create a list which mixes them in alternate order.  I started with:

    umbraco.library:GetXmlNodeById($source)/descendant-or-self::node

    ...passing in the Newsroom itself as the Id (the Parent of News anud Press Releases).  I was thinking I would then check to see whose PARENT is News or Press Releases; this would at least narrow it down.  But that doesn't even DEAL with the alternate sort.  I am not advanced enough in XSLT to pull this off.  Does anyone have any ideas on how to do this?

    Thanks in advance,

    Garrett

  • Thomas Höhler 1237 posts 1709 karma points MVP
    Nov 10, 2009 @ 23:27
    Thomas Höhler
    0

    Sorting and especially grouping is worse in xslt 1.0, in this cases I would recommend doing an own xslt-extension using the umbraco.presentation.nodefactory.node which creates you the sorted list. I can give you an example tomorrow.

    Thomas

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Nov 10, 2009 @ 23:49
    Chriztian Steinmeier
    2

    Hi Garrett,

    Here's a example of how it could be done with XSLT, hopefully the comments are sufficient help - otherwise feel free to ask about what's happening:

    <?xml version="1.0" encoding="utf-8" ?>
    <xsl:stylesheet
        version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:exslt="http://exslt.org/common"
    >
        <xsl:param name="currentPage" />
    
        <xsl:variable name="root" select="$currentPage/ancestor-or-self::root" />
    
        <xsl:variable name="news" select="$root//node[../@nodeTypeAlias = 'Newsroom']" />
        <xsl:variable name="press" select="$root//node[../@nodeTypeAlias = 'Press Releases']" />
    
        <!-- Number of recent items wanted -->
        <xsl:variable name="itemsToShow" select="5" />
    
        <!-- Sort and reject -->
        <xsl:variable name="newsSorted">
            <xsl:for-each select="$news">
                <!-- Sort using createDate - use whatever fits  -->
                <xsl:sort select="@createDate" data-type="text" order="descending" />
                <xsl:if test="position() &lt;= $itemsToShow">
                    <xsl:copy-of select="." />
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
    
        <!-- Sort and reject -->
        <xsl:variable name="pressSorted">
            <xsl:for-each select="$press">
                <xsl:sort select="@createDate" data-type="text" order="descending" />
                <xsl:if test="position() &lt;= $itemsToShow">
                    <xsl:copy-of select="." />
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
    
        <!-- Here we go  -->
        <xsl:template match="/">
            <xsl:for-each select="exslt:node-set($newsSorted)/node">
                <xsl:variable name="pos" select="position()" />
    
                <!-- Render News item -->
                <xsl:apply-templates select="." />
    
                <!-- Render Press Release -->
                <xsl:apply-templates select="exslt:node-set($pressSorted)/node[$pos]" />
            </xsl:for-each>
        </xsl:template>
    
        <!-- Template for output of the node elements -->
        <xsl:template match="node">
            <p>
                <xsl:value-of select="@nodeName" />
            </p>
        </xsl:template>
    
    </xsl:stylesheet>

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Nov 11, 2009 @ 19:40
    Garrett Fisher
    0

    Wow, I really appreciate your attention (and generosity!).  I've applied your code to my XSLT file, and am gettnig the followiong error:

    System.Xml.Xsl.XslLoadException: Prefix 'exslt' is not defined. An error occurred at c:\inetpub\wwwroot\xslt\633935434871394745_temp.xslt(45,4).

    Any ideas?

    Thanks again,

    Garrett

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Nov 11, 2009 @ 20:19
    Chriztian Steinmeier
    0

    You're welcome :-)

    OK, easiest fix for this is probably to find the 2 calls to exslt:node-set in the XSLT file, and replace them with msxml:node-set, if you're using one of the standard XSLT files supplied by Umbraco.

    Otherwise, let me know and I'll provide a full refund with an explanation :-)

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Nov 11, 2009 @ 20:28
    Garrett Fisher
    0

    After some research, I've managed to get rid of this error by adding:

    xmlns:exslt="http://exslt.org/common"

    The output of the stylesheet, however, is empty:

    <!--  -->       
    <!-- #headlines -->

    How do I translate this XSLT file into the template itself?  Should I be calling a Macro which uses this file?  If so, what type of Macro is it (List subpages from a changeable source, etc.)? 

    Thanks again,

    Garrett

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Nov 11, 2009 @ 21:13
    Chriztian Steinmeier
    0

    Hi Garrett,

    First, let's make sure the reason you're getting no output is not related to the namespace problem above. My solution makes use of an extension function (node-set) which is not included in XSLT 1.0, but rather is provided by either the Exslt project (http://exslt.org) or a Microsofts XSLT extension. If you just use the msxml:nodes-set version (and a standard Umbraco XSLT file as base) instead of exslt:node-set we should be ready to go.

    Lines 11 & 12 in the snippet above sets up the two main sections you want to pull data (i.e., subpages) from, so naturally the nodetype aliases in those lines need to reflect the ones you've created.

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Nov 11, 2009 @ 21:37
    Garrett Fisher
    0

    They do.  The nodeTypeAliases are correct (News and PressReleases).  These nodeTypeAliases should be the node types of the Parent pages whose Children I want to get, right? Or the node type of the Children themselves?

    I have changed the exslt: references to msxml:.  But neither scenario above outputs anything. YET ;)  I'll paste in my entire XSLT file here:

    <?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:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary"
    exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">

    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:param name="currentPage"/>

    <xsl:variable name="root" select="$currentPage/ancestor-or-self::root" />

    <xsl:variable name="news" select="$root//node[../@nodeTypeAlias = 'News']" />
    <xsl:variable name="press" select="$root//node[../@nodeTypeAlias = 'PressReleases']" />

    <!-- Number of recent items wanted -->
    <xsl:variable name="itemsToShow" select="5" />

    <!-- Sort and reject -->
    <xsl:variable name="newsSorted">
    <xsl:for-each select="$news">
    <!-- Sort using createDate - use whatever fits -->
    <xsl:sort select="@createDate" data-type="text" order="descending" />
    <xsl:if test="position() &lt;= $itemsToShow">
    <xsl:copy-of select="." />
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>

    <!-- Sort and reject -->
    <xsl:variable name="pressSorted">
    <xsl:for-each select="$press">
    <xsl:sort select="@createDate" data-type="text" order="descending" />
    <xsl:if test="position() &lt;= $itemsToShow">
    <xsl:copy-of select="." />
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>

    <!-- Here we go -->
    <xsl:template match="/">
    <xsl:for-each select="msxml:node-set($newsSorted)/node">
    <xsl:variable name="pos" select="position()" />

    <!-- Render News item -->
    <xsl:apply-templates select="." />

    <!-- Render Press Release -->
    <xsl:apply-templates select="msxml:node-set($pressSorted)/node[$pos]" />

    </xsl:for-each>
    </xsl:template>

    <!-- Template for output of the node elements -->
    <xsl:template match="node">
    <p>
    <xsl:value-of select="@nodeName" />
    </p>
    </xsl:template>


    </xsl:stylesheet>

    What do you think my problem is here?

    //Garrett

  • Garrett Fisher 341 posts 496 karma points
    Nov 11, 2009 @ 21:52
    Garrett Fisher
    0

    FYI, this is going to go on the Home Page, so the structure is as follows:

    Home

       > Newsroom

            >> News

            >> Press Releases

    Understood?  So I'm not sure the ancestor-or-self call is exactly what I want here as the root.  Is this looking at the tree recursively?

    //Garrett

     

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Nov 12, 2009 @ 00:38
    Chriztian Steinmeier
    0

    Hey Garrett,

    With a fresh CWS install, I've just tried to create a new XSLT file (+ macro), pasted your full XSLT code, and modified the $news and $press selections to pick the nodes under the 'Gallery' node (../@nodeTypeAlias = 'CWS_Gallery') and likewise for the 'News and Events' node (../@id = '1096']).

    Then I put the macro in the Master template at the bottom, and hit the homepage - voila, working output...

    So you'd wanna take an extra look at the nodeTypeAliases you specify. You can easily test if they catch anything by putting these lines into the rootnode template (the one that says: match="/"):

    <textarea rows="8" cols="40"><xsl:copy-of select="$news" /></textarea>
    <textarea rows="8" cols="40"><xsl:copy-of select="$press" /></textarea>
    If you're not getting some XML nodes in these textareas, your aliases don't match the ones defined (they're case-sensitive, by the way)...
    Hope you're getting there :-)
    /Chriztian 

  • Garrett Fisher 341 posts 496 karma points
    Nov 12, 2009 @ 17:05
    Garrett Fisher
    0

    When I put the textareas in:

            <!-- Here we go  -->
    <xsl:template match="/">

    <textarea rows="8" cols="40"><xsl:copy-of select="$news" /></textarea>
    <textarea rows="8" cols="40"><xsl:copy-of select="$press" /></textarea>

    <xsl:for-each select="msxml:node-set($newsSorted)/node">
    <xsl:variable name="pos" select="position()" />

    <!-- Render News item -->
    <xsl:apply-templates select="." />

    <!-- Render Press Release -->
    <xsl:apply-templates select="msxml:node-set($pressSorted)/node[$pos]" />

    </xsl:for-each>
    </xsl:template>

    I get very strange behavior.  Whatever HTML comes after this in the Master template is CONTAINED IN the textarea.  And still no News items or Press Release items.  Just to be clear, again, the nodeTypeAliases are correct (News and PressReleases), assuming that hese nodeTypeAliases should be the node types of the PARENT pages whose Children I want to get, right? Or should they be the node types of the Children themselves?  Not that this works either, because it doesn't.  So in your test, you have Children under CWS_Gallery and News/Events and you are seeing them running this XSLT?  I don't know how.  I can't fugure out what is different between what we're doing.  How can I see if

    <xsl:variable name="press" select="$root//node[../@nodeTypeAlias = 'PressReleases']" />

    Has any meaning?

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Nov 12, 2009 @ 17:17
    Chriztian Steinmeier
    0

    The reason the HTML gets caught in the textarea(s) is because the $press and $news are empty - so they're not catching anything.

    Yes, the aliases are PARENT pages.

    Yes, I get the expected behaviour on the CWS test.

    Try to dump the complete XML (copy-of select="$root") in the textarea and make sure that the childnodes you expect to appear are indeed present (published) and children of said nodeTypes.

    /Chriztian 

  • Garrett Fisher 341 posts 496 karma points
    Nov 12, 2009 @ 17:32
    Garrett Fisher
    0

    Chriztian-- I'm getting somewhere now, thanks to your (../@id = '1096']) hint!

    I ended up having to use ID's instead of nodeTypeAliases. For some reason, these just weren't working....  By the way, this is VERY good code, and I expect to reuse it-- thanks very much for showing me the msxml:node-set method.  It's very powerful.

    So, I am getting One News, One Press Release, One News, One Press Release, One News, One Press Release, etc.  This is exactly what I wanted.  Thanks again!

    //Garrett

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Nov 12, 2009 @ 23:16
    Chriztian Steinmeier
    0

    You're welcome Garrett, anytime...

    /Chriztian 

Please Sign in or register to post replies

Write your reply to:

Draft