Im working on at site, where i need to list data from facebook updates, youtube rss, and umbraco.
I've pretty much got it down to get the data from both sources by themselves. The problem is i need to sort them by date/time in between each other. And im a bit lost how to go about this.
What im trying to achieve is something like this (simplified)
<ul> <li>Youtube video from channel 01 - time10:38</li> <li>Facebook update from profile 02 - time10:55</li> <li>Facebook update from profile 01 - time11:01</li> <li>Facebook update from profile 01 - time11:04</li> <li>Umbraco News page - time11:15</li> <li>Youtube video from channel 02 - time11:30</li> <li>Youtube video from channel 01 - time12:30</li> </ul>
One thing
you could do (there may be a better way) is to create a variable and
add the nodes from each of the 3 feeds to it using a standard format,
then do your for-each and sorting on that variable.
Alright, so i kinda saw the light from your post there Chriztian, it helped a lot. But guess what, im stuck again :)
I got it working by manually inputting the feed urls, but i would like to have the site editor be able to add feeds from the ui.
I have a folder in the content node tree where the editor can create new "Feed" nodes with a text parameter "feedUrl" on the document type for inputting the url.
As i see it, i need to:
1. iterate through these nodes, and create variables from the "feedUrl" field.
Oh - when you create the feedUrls in content you can leverage the powerful document() function - if you send it a node-set instead of a URL, it'll treat every node as a URL and fetch 'em all in one go - so here we go:
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:umbraco.library="urn:umbraco.library"
xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes"
exclude-result-prefixes="umbraco.library"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:param name="currentPage" />
<!-- Grab a reference to the site root (usually on level 1) -->
<xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*[@level = 1]" />
<xsl:template match="/">
<!-- NOTE: You may need to change this XPath, to point to where the feedUrl properties are --><xsl:variable name="feeds" select="document($siteRoot/Feeds/Feed/feedUrl)" />
<!-- Yes - everything is inside $feeds at this point - magic :-) -->
<xsl:apply-templates select="$feeds//item">
<!-- Horrendous RFC822 date format is not suitable for sorting, so... -->
<xsl:sort select="Exslt.ExsltDatesAndTimes:formatdate(substring(pubDate, 0, 26), 'yyyy-MM-ddTHH:mm:ss')" order="descending" />
</xsl:apply-templates>
</xsl:template>
<!-- Template for an item -->
<xsl:template match="item">
<xsl:if test="position() < 30">
<div>
<p style="margin:0px;">
<xsl:apply-templates select="pubDate" mode="date" /><br/>
<xsl:apply-templates select="title" />
<xsl:apply-templates select="link[contains(., 'youtube')]" />
</p>
<xsl:if test="not(contains(link, 'facebook'))">
<xsl:choose>
<xsl:when test="string(100) != '0'"><!-- Did you mean: string-length(../description > 100) ? -->
<p style="margin:0px;">
<xsl:value-of select="umbraco.library:TruncateString(umbraco.library:StripHtml(../description), 100, '...')" disable-output-escaping="yes" />
</p>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="../description" disable-output-escaping="yes" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</div>
</xsl:if>
</xsl:template>
<xsl:template match="title">
<a href="{../link}">
<xsl:if test="normalize-space(../author)"><xsl:value-of select="author"/><br/></xsl:if>
<xsl:value-of select="." />
</a>
</xsl:template>
<!-- Format date as LongDate -->
<xsl:template match="pubDate" mode="date">
<xsl:value-of select="umbraco.library:LongDate(substring(., 0, 26))" />
</xsl:template>
<!-- YouTube entry -->
<xsl:template match="link[contains(., 'youtube')]">
<xsl:variable name="myyoutube" select="substring(., 32, 11)" />
<iframe width="250" height="150" src="http://www.youtube.com/embed/{$myyoutube}" frameborder="0" allowfullscreen="true"><xsl:comment /></iframe>
</xsl:template>
</xsl:stylesheet>
I did some other stuff to your code, I know - but I need to spread the "apply-templates virus" to every corner of the world, so... :-)
This is so insanely cool. Thanks a bunch. Im 99% there. 1 last thing though (I hope ;) )
As you can see, i have a <div> around every post. I would like to define eg. a background color on the different feeds. On a feed level... not on a post level.
Being naive i thought i could just do something like:
It's not *that* naïve to think you can do that - but you as I always say: "Remember that you get a *set* back from a select." - so when you say $siteRoot/Feeds/Feed/bgcolor - you're actually getting all the bgcolor elements back, but when you ask for the value-of a set, the processor returns the value from the first in the set.
So you need to get the bgcolor that sits on the Feed node that has the same feedUrl as the item you're rendering... so how to get that? If you're lucky, the feeds you're fetching will have an atom:link with a rel="self" attribute - the href atribute on that element should have the URL of the feed, so something like this (remember to add the namespace for the atom prefix):
(I checked a couple of the feeds you supplied earlier, which has the URL - it sits on an atom10:link element, but through the beauty of namespaces the prefix don't mean a damn thing - pardon my french :-)
Well not really... 30 is the numer of items i wnat to show in total.
What im looking to do is to limit each feed to e.g. 5.
The reason is, if i have, lets say 6 feeds. Taking the 5 newes from each will guarentee something from all of them gets shown. Otherwise some eager poster can swamp the list with his 30 daily facebook updates :).
The problem is the sorting. Ive overcome this by making a "pubDate" field on the umbraco nodes...
What i really would like to do is set the "pubDate" for the umbraco node to "currentdate" at all times, and then stream the time of day from @createDate.
This would keep the umbraco node at the top of the list, but let feed item mingle in between them during the day...
So the optimal solution would be to be able to sort on 2 parameters... E.g "pubDate" and "$myDate"
Not entirely sure how you want it sorted (all Umbraco nodes first?) - but you can do something like this, where multiple sort statements are used, but their select attributes are constructed in a way that they're "mutually exclusive":
sorting data from multiple external sources
Im working on at site, where i need to list data from facebook updates, youtube rss, and umbraco.
I've pretty much got it down to get the data from both sources by themselves.
The problem is i need to sort them by date/time in between each other.
And im a bit lost how to go about this.
What im trying to achieve is something like this (simplified)
<ul>
<li>Youtube video from channel 01 - time10:38</li>
<li>Facebook update from profile 02 - time10:55</li>
<li>Facebook update from profile 01 - time11:01</li>
<li>Facebook update from profile 01 - time11:04</li>
<li>Umbraco News page - time11:15</li>
<li>Youtube video from channel 02 - time11:30</li>
<li>Youtube video from channel 01 - time12:30</li>
</ul>
You could probably use the
where @sTime would be the date-time variable
Remember: <xsl:sort/> must be always the first line within the <xsl:for-each/> if used.
Cool... Any idea how to merge 2 or more sources, like 3 facebook status feeds and 2 youtube channels?
One thing you could do (there may be a better way) is to create a variable and add the nodes from each of the 3 feeds to it using a standard format, then do your for-each and sorting on that variable.
Ex:
Not sure what the structure of the feeds are so obviously you'll need to adjust/add attributes or elements to each <node>, etc.
Hope this helps,
Tom
Hi Claus (+ Tom),
Actually, you can join all the nodes from various variables using a pipe character in a select, e.g.:
But, you might need to get a little creative with the sort select, unless all sources have identical "datetime" data...
How do they look?
/Chriztian
Alright, so i kinda saw the light from your post there Chriztian, it helped a lot. But guess what, im stuck again :)
I got it working by manually inputting the feed urls, but i would like to have the site editor be able to add feeds from the ui.
I have a folder in the content node tree where the editor can create new "Feed" nodes with a text parameter "feedUrl" on the document type for inputting the url.
As i see it, i need to:
1. iterate through these nodes, and create variables from the "feedUrl" field.
2. pass these variables to the <xsl:with-param
But how do i go about these two steps?
My current working code is below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<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.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltDatesAndTimes">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:variable name="feedContent" select="umbraco.library:GetXmlDocumentByUrl('http://feeds.feedburner.com/ClausHingebjergsFacebookStatusUpdates')"/>
<xsl:variable name="feedContent2" select="umbraco.library:GetXmlDocumentByUrl('http://feeds.feedburner.com/UploadsByProffartholstebro')"/>
<xsl:variable name="feedContent3" select="umbraco.library:GetXmlDocumentByUrl('http://feeds.feedburner.com/borsen/wqUp')"/>
<xsl:variable name="feedContent4" select="umbraco.library:GetXmlDocumentByUrl('http://feeds.feedburner.com/CeramicspeedsFacebookWall')"/>
<xsl:variable name="feedContent5" select="umbraco.library:GetXmlDocumentByUrl('http://jp.dk/jptv/?service=rssfeed')"/>
<xsl:call-template name="renderFeed">
<xsl:with-param name="feedContent" select="$feedContent | $feedContent2 | $feedContent3 | $feedContent4 | $feedContent5"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="renderFeed">
<xsl:param name="feedContent"/>
<xsl:for-each select="$feedContent//item">
<xsl:sort select="Exslt.ExsltDatesAndTimes:formatdate(substring (pubDate, 0, 26), 'yyyy-MM-ddTHH:mm:ss')" order="descending" />
<xsl:if test="position() < 30">
<div>
<p style="margin:0px;"><xsl:value-of select="umbraco.library:LongDate(substring (pubDate, 0, 26))"/><br/>
<a href="{link}">
<xsl:if test="author !=''"><xsl:value-of select="author"/><br/>
</xsl:if>
<xsl:value-of select="title"/>
</a>
<xsl:if test="contains(link, 'youtube')">
<xsl:variable name="myyoutube" select="substring (link, 32, 11)"/>
<iframe width="250" height="150" src="http://www.youtube.com/embed/{$myyoutube}" frameborder="0" allowfullscreen="true">.</iframe>
</xsl:if>
</p>
<xsl:if test="not(contains(link, 'facebook'))">
<xsl:choose>
<xsl:when test="string(100) != '0'">
<p style="margin:0px;">
<xsl:value-of select="umbraco.library:TruncateString(umbraco.library:StripHtml(description), number(100), '...')" disable-output-escaping="yes"/>
</p>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="description" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</div>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Hi Claus,
Oh - when you create the feedUrls in content you can leverage the powerful document() function - if you send it a node-set instead of a URL, it'll treat every node as a URL and fetch 'em all in one go - so here we go:
I did some other stuff to your code, I know - but I need to spread the "apply-templates virus" to every corner of the world, so... :-)
/Chriztian
Wow, very awesome info Chriztian (as always) - thanks!
This is so insanely cool. Thanks a bunch. Im 99% there. 1 last thing though (I hope ;) )
As you can see, i have a <div> around every post. I would like to define eg. a background color on the different feeds. On a feed level... not on a post level.
Being naive i thought i could just do something like:
But that colors all feeds the same color... I guess im scoping something wrong... But whaaaaat :)
Ahh another thing ;). How do i limit the number of posts from each feed, say i only want the 5 newest from each?
Hi Claus,
It's not *that* naïve to think you can do that - but you as I always say: "Remember that you get a *set* back from a select." - so when you say $siteRoot/Feeds/Feed/bgcolor - you're actually getting all the bgcolor elements back, but when you ask for the value-of a set, the processor returns the value from the first in the set.
So you need to get the bgcolor that sits on the Feed node that has the same feedUrl as the item you're rendering... so how to get that? If you're lucky, the feeds you're fetching will have an atom:link with a rel="self" attribute - the href atribute on that element should have the URL of the feed, so something like this (remember to add the namespace for the atom prefix):
/Chriztian
Regarding the 5 newest - doesn't that conflict a little with your previous top 30 clause? Or did the specs change? :-)
As you can't sort inside a select, you'll probably have to do some grouping on the feedUrl, and then sort and pick by position... hmmm...
/Chriztian
Well not really... 30 is the numer of items i wnat to show in total.
What im looking to do is to limit each feed to e.g. 5.
The reason is, if i have, lets say 6 feeds. Taking the 5 newes from each will guarentee something from all of them gets shown. Otherwise some eager poster can swamp the list with his 30 daily facebook updates :).
Hope this makes sense
Ok, im soooo close now :) im starting to mix the feeds with umbraco nodes and it works, sorta...
<xsl:template match="/">
<xsl:variable name="feeds" select="document($siteRoot/Feeds/Feed/feedUrl)" />
<xsl:apply-templates select="$feeds//item | umbraco.library:GetXmlNodeById(1090)/*">
<xsl:sort select="Exslt.ExsltDatesAndTimes:formatdate(substring(pubDate, 0, 26), 'yyyy-MM-ddTHH:mm:ss')" order="descending" />
</xsl:apply-templates>
</xsl:template>
The problem is the sorting. Ive overcome this by making a "pubDate" field on the umbraco nodes...
What i really would like to do is set the "pubDate" for the umbraco node to "currentdate" at all times, and then stream the time of day from @createDate.
This would keep the umbraco node at the top of the list, but let feed item mingle in between them during the day...
So the optimal solution would be to be able to sort on 2 parameters... E.g "pubDate" and "$myDate"
Any ides how to go about this.?
Hi Claus,
Not entirely sure how you want it sorted (all Umbraco nodes first?) - but you can do something like this, where multiple sort statements are used, but their select attributes are constructed in a way that they're "mutually exclusive":
/Chriztian
(Man this logout thing on Our is getting tedious...)
I wnat to do a complete mashup, everything sorted in one big list, rss items and umbraco nodes in one big list. I need it mixed :)
is working on a reply...