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
    Feb 18, 2014 @ 20:34
    Garrett Fisher
    0

    List of Unique Years - generate-id() Problems

    Hi,

    I am currently attempting in XSLT to generate a list of unique year values from a nodeset of news items.  I have always had a lot of success using the so-called Meunchian method (generate-id()) for this type of thing but for some reason, in this case, several year values are missing from the list, even though there are definitely items which have those (missing) values.  Result is 2014 | 2010 | 2009 but should in reality include 2013, 2012, and 2011 as well.  Can anyone tell what I am doing wrong here?  I would appreciate the help as I am stumped!

    <?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" xmlns:ucomponents.cms="urn:ucomponents.cms" xmlns:ucomponents.dates="urn:ucomponents.dates" xmlns:ucomponents.email="urn:ucomponents.email" xmlns:ucomponents.io="urn:ucomponents.io" xmlns:ucomponents.media="urn:ucomponents.media" xmlns:ucomponents.members="urn:ucomponents.members" xmlns:ucomponents.nodes="urn:ucomponents.nodes" xmlns:ucomponents.random="urn:ucomponents.random" xmlns:ucomponents.request="urn:ucomponents.request" xmlns:ucomponents.search="urn:ucomponents.search" xmlns:ucomponents.strings="urn:ucomponents.strings" xmlns:ucomponents.urls="urn:ucomponents.urls" xmlns:ucomponents.xml="urn:ucomponents.xml" xmlns:autofolders.library="urn:autofolders.library" xmlns:PS.XSLTsearch="urn:PS.XSLTsearch"
      exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ucomponents.cms ucomponents.dates ucomponents.email ucomponents.io ucomponents.media ucomponents.members ucomponents.nodes ucomponents.random ucomponents.request ucomponents.search ucomponents.strings ucomponents.urls ucomponents.xml autofolders.library PS.XSLTsearch ">

    <xsl:output method="xml" omit-xml-declaration="yes" />
    <xsl:variable name="contentType" select="/macro/contentType"/>

    <xsl:param name="currentPage"/>
    <xsl:variable name="currentLanguage" select="$currentPage/ancestor-or-self::*[name() = 'Home']/language" />
    <xsl:key name="uniqueYear" match="*" use="substring(datePosted,0,5)"/>

    <xsl:variable name="year">
      <xsl:choose>
        <xsl:when test="normalize-space(umbraco.library:RequestQueryString('year'))">
          <xsl:value-of select="umbraco.library:RequestQueryString('year')"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="Exslt.ExsltDatesAndTimes:year()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:template match="/">

    <xsl:variable name="selectedPages">
      <xsl:choose>
        <xsl:when test="$currentPage/@nodeName = 'Media' or $currentPage/@nodeName = 'Press Releases'">
          <root>
            <xsl:copy-of select="$currentPage/* [name() = $contentType][substring(datePosted,0,5) = $year]"/>
          </root>
        </xsl:when>
        <xsl:otherwise>
          <root>
            <xsl:copy-of select="$currentPage/* [name() = $contentType]"/>      
          </root>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
     
    <xsl:if test="$currentPage/@nodeName = 'Press Releases'">
      <xsl:variable name="allPagesPR" select="$currentPage/* [name() = $contentType and @isDoc]"/>
      <div class="mini-page-nav">
        <a name="y">&nbsp;</a>
        <xsl:for-each select="$allPagesPR [generate-id() = generate-id(key('uniqueYear', substring(datePosted,0,5))[1])]">
          <xsl:sort select="substring(datePosted,0,5)" data-type="number" order="descending"/>
            <xsl:choose>
              <xsl:when test="substring(datePosted,0,5) = $year">
                <strong><xsl:value-of select="substring(datePosted,0,5)"/></strong>
              </xsl:when>
              <xsl:otherwise>
                <a href="?year={substring(datePosted,0,5)}#y">
                  <xsl:value-of select="substring(datePosted,0,5)"/>
                </a>
              </xsl:otherwise>
            </xsl:choose>
          <xsl:if test="position() != last()"> | </xsl:if>
        </xsl:for-each>
        &nbsp;
      </div>
    </xsl:if>
      
    <div class="tabbedListHolder">

      <xsl:choose>
        <xsl:when test="count(msxml:node-set($selectedPages)/root/*) &gt; 0">
            
            <xsl:for-each select="msxml:node-set($selectedPages)/root/*">
      
              <xsl:sort select="datePosted" order="descending"/>
              
              ....blah blah blah
              
            </xsl:for-each>
          
        </xsl:when>
        <xsl:otherwise>
          <p>No items found in <xsl:value-of select="$currentPage/@nodeName"/>.</p>
        </xsl:otherwise>
      </xsl:choose>
      
    </div>

    </xsl:template>

    <xsl:template name="FirstWords">
      
        <xsl:param name="words"/>
        <xsl:param name="text"/>

        <xsl:if test="$words &gt;= 1">
            <xsl:if test="umbraco.library:LastIndexOf($text, ' ') &gt; 0">
                <xsl:value-of select="substring-before($text, ' ')" disable-output-escaping="yes"/><xsl:text> </xsl:text>
            </xsl:if>
            <xsl:if test="umbraco.library:LastIndexOf($text, ' ') &lt;= 0">
                <xsl:value-of select="$text" disable-output-escaping="yes"/><xsl:text> </xsl:text>
            </xsl:if>

            <xsl:call-template name="FirstWords">
                <xsl:with-param name="words" select="$words - 1"/>
                <xsl:with-param name="text" select="substring-after($text, ' ')"/>
            </xsl:call-template>
        </xsl:if>

        <xsl:if test="$words = 1
                and umbraco.library:LastIndexOf($text, ' ') &gt; 0">
            <xsl:text>... </xsl:text>
        </xsl:if>

    </xsl:template>

    </xsl:stylesheet>

    Thanks,

    Garrett

     

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Feb 18, 2014 @ 21:30
    Chriztian Steinmeier
    0

    Hi Garrett,

    The only things I see (without having tried it or anything like that) are these two:

    1. Your key is indexing more nodes than you probably think it is ("" in the match attribute will index all properties as well - but with an empty string as the value - better to use "[@isDoc]" to only match document nodes)
    2. You're using 0, 5 to select the year - strings in XSLT are 1-based, so you should be using 1, 4 instead (makes more sense too, right?)

    Both of these shouldn't really affect the results, but I know XSLT processors vary, so might be something there...

    I'll try to test your code and see what I come up with though...

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Feb 18, 2014 @ 21:49
    Garrett Fisher
    0

    Thanks as usual for your always-timely reply, Chriztian.  As for the substring 1,4 -- you are absolutely right -- yes, makes much better sense.  I've modified that now.  No difference in the output.  As for the indexing key, although I could certainly match only documents (match="*[@isDoc]"), remember, our problem is not that we are getting too many results, but that we aren't getting enough!  Matching against *[@isDoc] yields the same result -- missing 2013, 2012, and 2011, even though all those years are well-represented in the database.  All children are the same document type and use the Date Picker field, all dates are populated, and all pages are published. 

    //Garrett

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Feb 18, 2014 @ 22:09
    Chriztian Steinmeier
    100

    Hi again - you're welcome :)

    I totally agree with your thoughts about the key - only reason I mention it is for those copying the basics from here, then modifying the use attribute, and suddenly getting wildly crazy results x)

    So I've been testing this with some made-up data, but everything works as expected, so I have another idea, which I'm about to bet you a beer on...:

    My guess is that you've got other types of nodes using the datePosted property... - remember, the Muenchian trick compares a node in a set of nodes with the first node returned from the key - Now, the key returns nodes from all over the entire structure, so let's say you have a Textpage somewhere before the "Press Releases" node, and that Textpage has a datePosted property with the value 2013-12-11... ? Exactly — you won't get that value in the loop.

    If that's it, we'll need to modify the key to specifically index only nodes below the "Press Releases" node (or some other way of identifying them).

    Cheers,

    /Chriztian

  • Garrett Fisher 341 posts 496 karma points
    Feb 18, 2014 @ 22:27
    Garrett Fisher
    0

    That was it ;)

     Needed to be much more selective with the nodes matched for comparison.  

    Dang -- that's tricky!  Your discovery has gained me a better understanding of the xsl:key concept, thiough, so I don't think I'll have this problem again!  CHEERS, Chriztian!

    //Garrett

Please Sign in or register to post replies

Write your reply to:

Draft