selecting top X items from Xml using XSLT in Umbraco

4.4k views Asked by At

I have an Umbraco based blog and I want to display the top 10 posts in each category on the front page of my blog. Category is just another property on my Document Type.

Umbraco basically stores its contents as XML, so category is an element of my blog post xml.

I am using Blog4Umbraco as the base blog package on Umbraco and it stores blog posts ("documents") in a date based hierarchy of year/month/day. e.g. if I created a blog post "Help me with this" today, it would be under /2011/02/16/help-me-with-this.

I have xlst to display all posts. It iterates through each folder and then sorts on date. The problem is I only want the 10 most recent blog posts for each category. The following xslt displays selects all blog posts for a particular category. How do I limit it to only 10, given that I may have to span multiple folders (multiple days, months, or even years) to get 10?

<msxsl:script implements-prefix='ss' language='CSharp'>  
<![CDATA[
public string monthName(int monthNum)
{
DateTime date = new DateTime(1,monthNum,1);
return date.ToString("MMMM");
}
public int dayNumber(string date)
{
DateTime mydate = DateTime.Parse(date);
return mydate.Day;
}]]>
</msxsl:script>

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

<xsl:param name="currentPage"/>
<xsl:param name="topic" select="/macro/category"/>

<xsl:template match="/">
<div id="archive">
  <h3><xsl:value-of select="$topic" /></h3>
  <xsl:for-each select="$currentPage/ancestor-or-self::node [@nodeTypeAlias = 'Blog']/node [@nodeTypeAlias = 'DateFolder']">
  <xsl:sort select="number(@nodeName)" data-type="number" order="descending"/>
  <xsl:for-each select="./node [@nodeTypeAlias = 'DateFolder']">
  <xsl:sort select="number(@nodeName)" data-type="number" order="descending"/>

  <xsl:for-each select=".//node [@nodeTypeAlias = 'BlogPost']">
    <xsl:sort select="ss:dayNumber(@createDate)" data-type="number" order="descending"/>
  <xsl:if test="./data[@alias='topic'] = $topic">
  <div class="listing">
    <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a> <br/> 
    <small>
      Posted: <xsl:value-of select="umbraco.library:LongDate(@createDate)"/>
      By: <xsl:value-of select="@writerName"/><br />
    </small>
    <xsl:if test="string-length(./data [@alias = 'blogSummary']) = 0">
      <xsl:value-of select="substring(umbraco.library:StripHtml(./data [@alias = 'bodyText']), 1, 200)"/>...
    </xsl:if>

    <xsl:if test="string-length(./data [@alias = 'blogSummary']) &gt; 0">
      <xsl:value-of select="./data [@alias = 'blogSummary']"/>
    </xsl:if>


  </div>
  </xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</div>
</xsl:template>
1

There are 1 answers

2
Dimitre Novatchev On BEST ANSWER

Instead of:

<xsl:for-each select=".//node [@nodeTypeAlias = 'BlogPost']">
    <xsl:sort select="ss:dayNumber(@createDate)"
          data-type="number" order="descending"/>
     <xsl:if test="./data[@alias='topic'] = $topic">
        <div class="listing">
          <!-- Some processing here -->
        </div>
     </xsl:if>
</xsl:for-each>

Use:

<xsl:for-each select=
   ".//node [@nodeTypeAlias = 'BlogPost']
                     [data[@alias='topic'] = $topic]
   ">
    <xsl:sort select="ss:dayNumber(@createDate)"
          data-type="number" order="descending"/>
     <xsl:if test="not(position() > 10)">
        <div class="listing">
          <!-- Some processing here -->
        </div>
     </xsl:if>
</xsl:for-each>