Copied to clipboard

Flag this post as spam?

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


  • JacoboPolavieja 62 posts 84 karma points
    Jul 18, 2010 @ 19:40
    JacoboPolavieja
    0

    Two separate sections: no repeating nodes

    Hello again,

     

    I know I am asking way too much... but I'm just starting both with Umbraco and XSLT, so it's kind of hard despite reading manuals and code.

    Anyway... I have two sections on my news page... one is for the "important" news (this is an attribute of the document type), and the other is for the latest news, either important or "normal" news. A picture says more.. so here it goes:

    http://yfrog.com/jmfrontpageaj

     

    As you see, in the upper section, it appears the last 6 "important" news. Everytime a later "important" new is added, the oldest one of the block goes out, and the recent one goes in.

    The thing is... in the lower section there might be "important" news (ONLY when they've been taken out by a more recent one in the upper section and there aren't lots of later no important news) as weel as non important. In short, in the lower section goes all the later news (up to 6 per region, important o non important) that aren't in the upper section.

    What I don't know how to control is the duplication of headlines in both sections. I mean... having one in the upper section and not having it in the lower one. For the upper i select the most recent 6 news with the attribute "important". For the lower part i select the latest 6 news which region coincides with the desired one. As such, there could happen that a new is in the upper section and the lower as well.

     

    Any way to check that?

     

    Thanks!

     

    P.S: Sorry for the long post and if you're a basketball fan... the headlines are just mock and invented, don't believe any of them! hahaha!

  • Rich Green 2246 posts 4008 karma points
    Jul 18, 2010 @ 20:17
    Rich Green
    1

    Hey,

    I don't have a code example but what you can do is:

    -- Loop through the 6 'important' news items build up a comma separated string of their node id's (like 6,8,14,16,20,30) 

           -- Add a comma each end to get ,6,8,14,16,20,30,

           -- Then in the bottom sections when you are looping through the news you can check to see if the current node id matches any in the list using the xslt CONTAINS function, something like

    contains(',6,' , ',6,8,14,16,20,30,')

    In the above example 6 is your current news id and the rest are the ones marked 'important' which are used in the important section (the commas are wrapped around to make sure '6' doesn't equal '66'). Using this information you can choose not to display the ones where the above match is true.

    Hope that makes sense, sorry i don't have time to show you a code example!

    Rich

  • Hendrik Jan 71 posts 137 karma points
    Jul 18, 2010 @ 20:53
    Hendrik Jan
    0


    I didnt test this, but in the bottom section loop you can test if the current node is in the important news section like this:

    <xsl:if test="string(./important) = '0' or count($newsItems [position() &lt; 7][./@id = @id]) = 0">
      <!-- i am not in the important news-section -->
    </xsl:if>

  • JacoboPolavieja 62 posts 84 karma points
    Jul 19, 2010 @ 10:23
    JacoboPolavieja
    0

    Thank you both! I can't try this out now because I'm not on the computer with the Umbraco installation (and have no access to it otherwise) but as soon as I try something I'll get you back with the results.

     

    Thanks a lot!

  • Rich Green 2246 posts 4008 karma points
    Jul 19, 2010 @ 11:21
    Rich Green
    0

    Neils solution is way more elegant than mine, so I'd recommend trying his!

    Best of luck

    Rich

  • JacoboPolavieja 62 posts 84 karma points
    Jul 24, 2010 @ 12:45
    JacoboPolavieja
    0

    Hello again!

     

    Sorry to get back to you so late! I have been trying to accomplish the mission with no success so far... If you wouldn't mind looking at how my code operates right now and suggest a good approach it'd be great.

     

    So, to refresh... I have two sections. In the first one I want to put the lastest 6 news that have the "important" attribute checked. This is done with the following code:

    <xsl:variable name="documentTypeAlias" select="string('thm_new')"/>

    <xsl:template match="/">

    <!-- The fun starts here -->
    <xsl:for-each select="$currentPage/* [name() = $documentTypeAlias and string(umbracoNaviHide) != '1' and thm_new_important = '1']">
      <xsl:sort select="@createDate" order="descending" />
      <xsl:if test="position() &lt; 7">

            <div class="new">
                    <img class="new_country" src="images/content/countries_titles/usa.gif" />
                    <img class="new_flag" src="images/content/flags/usa.jpg" />
                    <h1><xsl:value-of select="thm_new_heading"/></h1>
                    <p>
                            <span class="new_date">
                                    <xsl:value-of select="umbraco.library:FormatDateTime(@createDate, 'dd MMM')" />
                              <!-- TODO: The above should really be publication date! -->
                            - </span> <xsl:value-of select="thm_new_summary"/>
                            <br />
                      
                            <span class="new_readmore">
                                    <a href="{umbraco.library:NiceUrl(@id)}">Read more...</a>
                            </span>
                    </p>
            </div>
      </xsl:if>
    </xsl:for-each>

     

    Now on the other section I would have three colums generated like this (each for a different country):

    <div id="last_minute_section_usa">
      <h1>USA</h1>  
      
    <!-- The fun starts here -->
    <xsl:for-each select="$currentPage/* [name() = $documentTypeAlias and string(umbracoNaviHide) != '1' and thm_new_mainCountry = 'USA']">
    <xsl:sort select="@createDate" order="descending"/>
      <xsl:if test="position() &lt;= $numberOfItems">
                
          <div class="last_minute_new">
            <h2><a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="thm_new_heading"/></a></h2>
            <p><xsl:value-of select="thm_new_summary"/>.
            <span class="last_minute_new_time"><xsl:value-of select="umbraco.library:FormatDateTime(@createDate, 'dd MMM - HH:mm')" /></span></p>
          </div>
        
      </xsl:if>
    </xsl:for-each>
    </div>

     

    As expected, it repeats some news that have the attribute "thm_new_important" checked. I can disable that and see the lastest 6 non-important news, but I'd like to have both types in this second section only without repeating the "important" ones that may be in the upper (first) section.

     

    Seeing Niels code, I think in my case it would be something like this:

    <xsl:if test="string(./thm_new_important) = '0' or count($newsItems [position() &lt; 7][./@id = @id]) = 0">
     
    <!-- i am not in the important news-section -->
    </xsl:if>

    But I really don't know how to blend that with my code. I suppose I first would have to create the "newsItems" collection, shouldn't I?

     

    All this is within the same page... so I don't know if it'd help but it wouldn't be a matter doing it all on the same macro or on separate little ones.

     

    Any help wold be much much appreciated. It can't be that difficult but I'm certainly stuck!

     

    Thanks! Cheers!

     



  • webangelo 107 posts 190 karma points
    Jul 24, 2010 @ 20:15
    webangelo
    0

    Niels solution does assume that you have created a sorted node set called newsItems which at minimum contains the items you are displaying in your Important News section or more as long at it has the same filter and sort.  So try the following:

    <xsl:variable name="newsItems">
    <xsl:for-each select="$currentPage/* [name() = $documentTypeAlias and string(umbracoNaviHide) != '1' and thm_new_important = '1']">
               
    <xsl:sort select="@createDate" order="descending" />
      <xsl:if test="position() &lt; 7">
        <xsl:copy-of select="." />
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>

    Note that the code above will create a node set with only the first six Important nodes.  If you want all important nodes, leave off the xsl:if.

    You can now use this directly for your important news section. 

    <xsl:for-each select="msxml:node-set($newsItems)">

    You should also be able to run Niels filter now:

    <xsl:if test="string(./thm_new_important) = '0' or count($newsItems [position() &lt; 7][./@id = @id]) = 0">
     
    <!-- i am not in the important news-section -->
    </xsl:if>

    Although, if you used the if statement while creating it, you can leave off the [position() &lt; 7] part in this area as it becomes moot. BTW, if Niels code throws an error, try wrapping the $newsItems in a node-set function there too:

    <xsl:if test="string(./thm_new_important) = '0' or count(msxml:node-set($newsItems)
    [position() &lt; 7][./@id = @id]) = 0">
     
    <!-- i am not in the important news-section -->
    </xsl:if>

    Unfortunately, I didn't have time to create your specific scenario, so there may be a typo in some of the code, but hopefully you get the general idea.

  • JacoboPolavieja 62 posts 84 karma points
    Jul 25, 2010 @ 12:36
    JacoboPolavieja
    0

    Hi webangelo and thanks a lot for helping!

    I created the variable with your code. After that I go through the nodes like you put, only with a small modification because it threw an error. Looking at http://msdn.microsoft.com/en-us/library/hz88kef0%28VS.80%29.aspx I remodeled it as:

    <xsl:for-each select="msxml:node-set($newsItems)/thm_new">

    And it seems ok as that chunk outputs as expected.


    Now, on the second part... wether I put it either way (with or without the "msxml:node-set($newsItems)" it only outputs those which have thm_new_important = 0, but moreover, if I leave the test as is, the first section doesn't render and instead a "Error parsing XSLT file: \xslt\thm_frontpage_importantNews.xslt" message is displayed. So leaving it as is renders that message on the first section and outputs only the non important news on the second one. I've been commenting and uncommenting code and not surprisingly the error seems to be on the chunk of

    count(msxml:node-set($newsItems) [position() < 7][./@id = @id]) = 0

    I repeat... it doesn't matter wether I put it with the node-set or not. I'm no expert but if I don't interpret the code bad the intention is to say "display it if thm_new_important equals '0' or if the ID of the node isn't on the $newsItems collection", isn't it? In that case... in the count function above, is it supposed to iterate through the collection to check every item's ID is not the actual node's ID? I don't know if it does it automatically,

    Last, if I change the statement to be

    <xsl:if test="string(./thm_new_important) = '0' or count(msxml:node-set($newsItems)/thm_new [./@id = @id]) = 0">

    It doesn't give an error and displays the important news in the first section, but doesn't put the important news no in the first section in the second one.

     

    Ufff... this is being hard! Thanks a lot for helping. Hope it can be done in some way!

    Cheers!

    P.S: The entire file, if that can be of help although it now needs a serious code cleaning is here: http://pastebin.com/9YFFQzxb (it's the USA part the only one I'm trying to get right now)

     

  • JacoboPolavieja 62 posts 84 karma points
    Jul 26, 2010 @ 12:16
    JacoboPolavieja
    0

    I know it may not be the best solution, but as I'm being completely unable to make the testexpression work after having read lots of articles, I came up with this pseudo solution till I can achieve something better:

    1.  I create two collections: one for the 6 importantNews for the upper section, another one with the rest of news (important and nonImportant). This is achieved by ordering the list of news nodes by two criteria correctly and the same criteria on both lists (this is just to build the lists, not using them right away). "Important" attribute prevails the date so it sorts first on that and then on date.

    <xsl:variable name="importantNews">
    <xsl:for-each select="$currentPage/* [name() = $documentTypeAlias and string(umbracoNaviHide) != '1']">
      <xsl:sort select="thm_new_important" data-type="number" order="descending" />
      <xsl:sort select="@createDate" order="descending" />
      <xsl:if test="position() &lt; 7">
        <xsl:copy-of select="." />
      </xsl:if>
    </xsl:for-each>
    </xsl:variable>  
      
    <xsl:variable name="otherNews">
    <xsl:for-each select="$currentPage/* [name() = $documentTypeAlias and string(umbracoNaviHide) != '1']">
      <xsl:sort select="thm_new_important" data-type="number" order="descending" />
      <xsl:sort select="@createDate" order="descending" />

      <xsl:if test="position() &gt; 6">
        <xsl:copy-of select="." />
      </xsl:if>
    </xsl:for-each>
    </xsl:variable>

     

    2. With the two lists containing the right nodes it's just a matter of going through them, sorting the nodes again when needed (in this case, just in the second section as I want the date to prevail over the important attribute there):

    First section:

    <xsl:for-each select="msxml:node-set($importantNews)/thm_new">

            <div class="new">
                    <img class="new_country" src="images/content/countries_titles/usa.gif" />
                    <img class="new_flag" src="images/content/flags/usa.jpg" />
                    <h1><xsl:value-of select="thm_new_heading"/></h1>
                    <p>
                            <span class="new_date">
                                    <xsl:value-of select="umbraco.library:FormatDateTime(@createDate, 'dd MMM')" />
                              <!-- TODO: The above should really be publication date! -->
                            - </span> <xsl:value-of select="thm_new_summary"/>
                            <br />
                      
                            <span class="new_readmore">
                                    <a href="{umbraco.library:NiceUrl(@id)}">Read more...</a>
                            </span>
                    </p>
            </div>
      <!-- </xsl:if> -->
    </xsl:for-each>

    Second section:

    <div id="last_minute_section_usa">
      <h1>USA</h1>  
     
    <xsl:for-each select="msxml:node-set($otherNews)/thm_new">
     
    <xsl:sort select="@createDate" order="descending"/>

      <xsl:if test="thm_new_mainCountry='USA'">          
          <div class="last_minute_new">
            <h2><a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="thm_new_heading"/></a></h2>
            <p><xsl:value-of select="thm_new_summary"/>.
            <span class="last_minute_new_time"><xsl:value-of select="umbraco.library:FormatDateTime(@createDate, 'dd MMM - HH:mm')" /></span></p>
          </div>
        
      </xsl:if>
    </xsl:for-each>

     

    I know it's kind of shoddy, but it seems to wok while I find something better. Any help would be much appreciated ;).

     

    Thanks! Cheers!

Please Sign in or register to post replies

Write your reply to:

Draft