List entries with logic (recursion or sort/limit?)
This is an open discussion with 5 replies, filed under XSLT.
Search
I think there is a simpler way to do this:
<xsl:choose> <xsl:when test="$name"> <xsl:apply-templates select="interviews/entry[position() < 4][name/@handle != $name]" /> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="interviews/entry[position() < 5][name/@handle != $name]" /> </xsl:otherwise> </xsl:choose>
where you have a template that matches the interviews/entry
node:
<xsl:template match="interviews/entry"> <article class="interview"> <h1><xsl:value-of select="name" /></h1> <xsl:copy-of select="excerpt/*" /> </article> </xsl:template>
Edited to better match your XML.
I’m assuming that you are filtering the single interview by a URL parameter called $name
. Did I guess correctly?
I’ve been rereading your question and my response and realized that all you really need should be the following (although this untested and just off the top of my head):
To list four excerpts, you should be able to use the following apply-templates
instruction:
<xsl:apply-templates select="/data/interviews/entry[position() < 5][name/@handle != $name]" mode="excerpts" />
Then, the following match template should provide the expected output:
<xsl:template match="/data/interviews/entry" mode="excerpts"> <div class="threecol"> <xsl:if test="$count=4"> <xsl:attribute name="class"> <xsl:text>threecol last</xsl:text> </xsl:attribute> </xsl:if> <h3><a href="/interviews/{business/@handle}"><xsl:value-of select="name"/></a></h3> <p class="business_name"><xsl:value-of select="business"/></p> <p><xsl:copy-of select="excerpt/p/node()"/> <xsl:text> </xsl:text> <a href="/interviews/{business/@handle}">→Watch</a> </p> </div> </xsl:template>
There’s no need to use recursion or count your entries if you do your sorting in the data source and limit the output to the 5 latest entries. This should always output the latest 4 interviews.
Note: Not knowing the context, I modified this to match the root node, data
.
Also, you probably don’t need the mode="excerpts"
attribute on the match template. I just threw it in there, just in case you had other templates that might be matching that particular node.
Thanks!
Yes you are right on the $name
but I’m filtering the single interview by the business name which has a variable name of $interview (just to totally confuse things!) - but that is a quick fix!
Just tried your last idea but I’m having the same issue as before. Ie when I’m viewing one of the four most recent entries I only get 3 excerpts being displayed….
The reason I think is that we are using position()
to determine the number of excerpts to be outputted. However, the filtering of the data source in XSLT doesn’t change the actual position of an entry.
I.E if we assume we are currently viewing the entry that is in position 1 of interviews
. XSLT still considers that to be position 1 regards of if we filter it out or not. So when it gets to ‘position 4’ it stops even though it didn’t output the content from position 1.
I hope that makes sense - i’m not explaining it very well.
So i’m going to experiment with the xsl:choose
idea you suggested but modify it to try and change the output limit depending on if we are viewing one of the four most recent entries or not.
My brain hurts…
Ok so I got it working! The xsl:choose
was the key.
This is what I have.
<xsl:template name="latest"> <xsl:param name="current-int" select="/data/single-interview/entry/order"/> <xsl:param name="latest-entry" select="/data/interviews/entry[1]/order"/> <xsl:choose> <xsl:when test="$current-int > $latest-entry - 5"> <xsl:apply-templates select="/data/interviews/entry[position() < 6][business/@handle != $interview]" /> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="/data/interviews/entry[position() < 5][business/@handle != $interview]" /> </xsl:otherwise> </xsl:choose> </xsl:template>
With a template match that looks like this:
<xsl:template match="/data/interviews/entry"> <div class="threecol"> <xsl:if test="position() = 4"> <xsl:attribute name="class"> <xsl:text>threecol last</xsl:text> </xsl:attribute> </xsl:if> <a href="/interviews/{business/@handle}"> <h3><xsl:value-of select="name"/></h3> <p class="business_name"><xsl:value-of select="business"/></p> <p><xsl:copy-of select="excerpt/p/node()"/> </p> </a> </div> </xsl:template>
So i’m checking to see if the current entry is one of the first four entries and then outputting one extra to compensate for missing out entry out.
I’m limiting it to 6 and 5 because the position seems to start from 1 not from zero. So it has to be <: 5 to get four things out and < 6 when I’m skipping one.
The weird thing is that in the template-match
, the test for position()=4
still works even though in the case where the current interview is one of the four most recent it’s actually outputting content from the 5th position? Which is extra confusing!
If anyone can think of a better way to do this I’d love to hear it - seems like there should be something really simple but I can’t think of it.
Thanks for the help and ideas! Definitely helped finally crack it.
T
Create an account or sign in to comment.
Hi there,
I’ve been puzzling over this for days trying to work this out myself and I just can’t seem to get it to work how I would like.
Basically I have a blog style site set up with entries. You can see it here if interested: We Were Here
When i’m looking at the single article/interview page I want to output a list of the four most recent entries at the bottom of the page. Easy! But I want to have some simple logic so that if the article currently being viewed is one of the lastest four articles it doesn’t display that article but skips it and displays the next one instead. So there are always four but I never recommend the one they are already looking at.
Sounds easy but I just can’t get it to work!
There are two data sources
single-interview
which is filtered to only display one article based on a url parameter, andinterviews
which is a cut down version on the full feed.This is an example of the Interviews data source (obviously there are lots of entries but i’ve just shown one for simplicity). The interviews data source is ordered descending by the
order
node:Then there is the single interview data source that looks like this:
So what I thought was to create a param for the ‘current’ entry and then use recusion to output it four times and to not output anything if was the current entry.
But it didn’t work because the count would increment when nothing was outputting so I’d end up with one too few entries out putted. Or it would just stop at the current entry if I tried logic on the count itself…. If I could decrease $count by one somehow when it’s not outputting anything that would work but I have no idea how to do that!
So then I tried using
for-each
but limiting it to the first 4 positions:ie very similar to above but
But for some reason that doesn’t work either (haven’t got to the bottom of why to be honest?). It only outputs two entries (if i was viewing one of the first four) or three entries if I was viewing the 5th or later entry.
So now I’m stumped! All the xpath is right as stuff is being outputted but I can never seem to get the right number of entries no matter what I do.
Sorry this has been such a mega long post - just wanted to provide as much info as possible!
Any help very much appreciated!