Copied to clipboard

Flag this post as spam?

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


  • Bjorn Van Hoeymissen 27 posts 48 karma points
    Oct 14, 2010 @ 22:16
    Bjorn Van Hoeymissen
    0

    Copying and combining nodes, overwriting certain attributes

    Hi all,

    I have a list of newsitems that need to be sorted (most recent first). The thing is that it is a conditional sort of euhm sorts: newsitems have a datepicker so the client can antedate the articles if needed, but if the datepicker hasn't been used than the Umbraco lastUpdated property needs to be used.

    I was thinking of going over the newsitem nodes, copying them to a new nodeset and when the datepicker field (@newsDate) is empty, fill that attribute value with the Umbraco updateDate value. Then I can sort the new nodeset on the @newsDate attribute and start handling output.

    Not sure how to copy a node while changing an attribute's value. Been mucking around with apply-templates for the better part of the evening, with no result.

    Am I overcomplicating things? Is there an easier way to accomplish this? Or is this indeed the right course of action, and if so can anyone shed a light on how to copy the nodes to a new set? I clearly haven't gotten my "aha" moment yet when it comes to apply-templates (used to working with named templates and for-each).

    Thanks for any insights you can provide!

    PS: still using the old XML schema if that helps for code samples

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Oct 14, 2010 @ 22:58
    Chriztian Steinmeier
    0

    Hi Bjorn,

    Have you tried using two sort statements - usually you should be able to accomplish what you're trying to do with that:

    <xsl:apply-templates select="$currentPage/node[@nodeTypeAlias = 'NewsItem']">
        <xsl:sort select="data[@alias = 'newsDate']" data-type="text" order="descending" />
        <xsl:sort select="@updateDate" data-type="text" order="descending" />
    </xsl:apply-templates>
    

    Alternately, you can try concatenating the values in the sort (though I'm pretty sure that's essentially what using multiple statements do):

    <xsl:apply-templates select="$currentPage/node[@nodeTypeAlias = 'NewsItem']">
        <xsl:sort select="concat(data[@alias = 'newsDate'], @createDate)" data-type="text" order="descending" />
    </xsl:apply-templates>
    
    Otherwise, let me know, and I'll provide a sample for doing the copy stuff (which could be great for another task one day, anyways...)

    /Chriztian

  • Bjorn Van Hoeymissen 27 posts 48 karma points
    Oct 15, 2010 @ 06:03
    Bjorn Van Hoeymissen
    0

    Hi Chriztian,

    I had already tried your first suggestion, but that doesn't output the desired result: nodes gets sorted on the datepicker timestamp first, then on the Umbraco last updated timestamp. In this situation it means that all articles for which the client did not manually input a date (datepicker timestamp being empty) end up at the bottom of the sort order and those then get sorted on the last updated Umbraco date. So even though one of these could have been updated just five minutes ago, it'll only end up as the first of the nodes without a manual timestamp; not as first on the entire list.

    But your second solution worked a charm. So simple and elegant, I'm kicking myself for not thinking of it. Thanks heaps, Chriztian!

    If you have a spare moment, I wouldn't mind still finding out how to do the copy stuff though, for future reference :-)

    Thank you for your help,
    Bjorn

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Oct 15, 2010 @ 09:19
    Chriztian Steinmeier
    0

    Hi Bjorn - great you got it working!

    For future reference, here's the copy route - hopefully it's not complete gibberish :-)

       <!-- Build node-set -->
        <xsl:variable name="copyNewsItems">
            <!-- Make sure to optimize the XPath for finding the items, if at all possible... -->
            <xsl:apply-templates select="$currentNode/ancestor-or-self::*[@level = 1]//node[@nodeTypeAlias = 'NewsItem']" mode="copy" />
        </xsl:variable>
        <xsl:variable name="newsItems" select="msxsl:node-set($copyNewsItems)" />
    
        <!-- Root node template -->
        <xsl:template match="/">
            <div class="news">
                <xsl:apply-templates select="$newsItems">
                    <xsl:sort select="data[@alias = 'newsDate']" data-type="text" order="descending" />
                </xsl:apply-templates>
            </div>
        </xsl:template>
    
        <!-- Template for NewsItem output -->
        <xsl:template match="node[@nodeTypeAlias = 'NewsItem']">
            <div id="n{@id}">
                <h1><xsl:value-of select="@pageTitle" /></h1>
                <!-- ETC. -->
            </div>
        </xsl:template>
    
    
    <!-- :: Copy mode templates :: -->
    
        <!-- Copy template for NewsItem nodes -->
        <xsl:template match="node[@nodeTypeAlias = 'NewsItem']" mode="copy">
            <xsl:copy><!-- Copy element -->
                <xsl:copy-of select="@*" /><!-- Copy attributes -->
    
                <!-- Process properties -->
                <xsl:apply-templates select="data" mode="copy" />
            </xsl:copy>
        </xsl:template>
    
        <!-- Copy template for properties -->
        <xsl:template match="data" mode="copy">
            <xsl:copy-of select="." />
        </xsl:template>
    
        <!-- Template for empty newsDate properties -->
        <xsl:template match="data[@alias = 'newsDate'][not(normalize-space())]" mode="copy">
            <data alias="newsDate">
                <xsl:value-of select="parent::node/@updateDate" />
            </data>
        </xsl:template>
    
    It's using a common pattern in XSLT, where you just specify a couple of "copy" templates and a more specific one to change those specific elements (here, the empty newsDate properties).
    Have an ice weekend :-) 

    /Chriztian

  • Bjorn Van Hoeymissen 27 posts 48 karma points
    Oct 20, 2010 @ 10:44
    Bjorn Van Hoeymissen
    0

    Apologies for the slow reply, Chriztian, some important family matters intervened.

    That code does boggle the mind somewhat, I'll play around with the concept in some testcases to get my mind used to this way of tackling a problem. Certainly seems very powerful.

    Once again thank you for your excellent help!

Please Sign in or register to post replies

Write your reply to:

Draft