Best practice for xslt wanted! Options
fdo
Posted: Tuesday, February 05, 2008 8:00:45 PM

Rank: Enthusiast

Joined: 6/7/2007
Posts: 18
Location: Copenhagen, Denmark
Could anyone help me with best practice on “how to” create an xslt that gets news items, no matter where they are in the node structure, as long as the conditions for being displayed on the front page is meet.

On the front page, I want to show latest 16 news items. The news items on the front page comes from all sections/subsections news items, order by create date and priority. When a section creates a news item, the section decides, by true/false, if the news item are to be shown on the front page. The property is showOnFrontpage.

Alias for the document type is newsItem. There are no limits for sections or subsections.

How can I create the xslt, so it gets the news items only for the front page?

Example of structure:

Frontpage
-- Section 1
-- News area
-- News item 1
-- News item 2 (priority) (showOnFrontpage)
-- News item 3 (showOnFrontpage)
-- Another area
-- Another item 1
-- Section 2
-- News area
-- News item 1 (priority)
-- News item 2 (showOnFrontpage)
-- News item 3 (priority) (showOnFrontpage)
-- Subsection 2
-- News area
-- News item 1 (priority) (showOnFrontpage)
-- News item 2
-- News item 3
-- Another area
-- Another item 1
-- Section 3
-- News area
-- News item 1 (showOnFrontpage)
-- News item 2
-- News item 3 (priority) (showOnFrontpage)
-- Another area
-- Another item 1
etc…

Thanks in advance.

/Finn
fdo
Posted: Tuesday, February 05, 2008 8:09:48 PM

Rank: Enthusiast

Joined: 6/7/2007
Posts: 18
Location: Copenhagen, Denmark
Sorry for the double posting. Hopefully the formatting stays this time!

Could anyone help me with best practice on “how to” create an xslt that gets news items, no matter where they are in the node structure, as long as the conditions for being displayed on the front page is meet.

On the front page, I want to show latest 16 news items. The news items on the front page comes from all sections/subsections news items, order by create date and priority. When a section creates a news item, the section decides, by true/false, if the news item is to be shown on the front page. The property is showOnFrontpage.

Alias for the document type is newsItem. There are no limits for sections or subsections.

How can I create the xslt, so it gets the news items only for the front page?

Example of structure:

Frontpage
---- Section 1
--------- News area
---------- News item1
---------- News item 2 (priority) (showOnFrontpage)
---------- News item 3 (showOnFrontpage)
-------- Another area
------------ Another item1
---- Section 2
-------- News area
------------ News item1 (priority)
------------ News item 2 (showOnFrontpage)
------------ News item 3 (priority) (showOnFrontpage)
---------------- Subsection 2
-------------------- News area
------------------------- News item1 (priority) (showOnFrontpage)
------------------------- News item 2
------------------------- News item 3
-------- Another area
------------ Another item1
---- Section 3
-------- News area
------------ News item1 (showOnFrontpage)
------------ News item 2
------------ News item 3 (priority) (showOnFrontpage)
-------- Another area
------------ Another item1
Etc…

Thanks in advance.

/Finn
drobar
Posted: Tuesday, February 05, 2008 9:13:42 PM

Rank: Umbracoholic

Joined: 9/8/2006
Posts: 1,698
Location: KY, USA
Hi, Finn,

Let me be sure I understand what you want to do. Basically, you want to select all the nodes of nodeTypeAlias='newsItem' where data[@alias='showOnFrontpage'] = '1'

You then want to select the "best" ones to display by sorting the results by @createDate and then by data[@alias='priority'].

Then, you want to show the first 16 news items.

Is that correct?


cheers,
doug.

MVP 2007-2009 - Official Umbraco Trainer for North America - Percipient Studios
fdo
Posted: Tuesday, February 05, 2008 9:22:33 PM

Rank: Enthusiast

Joined: 6/7/2007
Posts: 18
Location: Copenhagen, Denmark
Hi Douglas

The 16 news items is sorted by create date and priority, meaning that for at given date the ones with priority is first.

Example:

news item 2 for 2008.02.05 10:22 (priority)
news item 4 for 2008.02.05 14:32
news item 3 for 2008.02.05 10:22
news item 1 for 2008.02.05 08:14
news item 2 for 2008.02.04 14:22 (priority)
news item 1 for 2008.02.04 10:32 (priority)
news item 3 for 2008.02.04 12:22
news item 2 for 2008.02.04 08:14

Hope it makes sense.

/Finn

fdo
Posted: Tuesday, February 05, 2008 9:36:38 PM

Rank: Enthusiast

Joined: 6/7/2007
Posts: 18
Location: Copenhagen, Denmark
Hi again Douglas

I was a little quick on the reply button!

Besides the clarifying on sort order, you are correct on what I want to accomplish.

/Finn
drobar
Posted: Tuesday, February 05, 2008 11:30:58 PM

Rank: Umbracoholic

Joined: 9/8/2006
Posts: 1,698
Location: KY, USA
That's very clear, thanks.

I'll work on it later tonight unless someone else gets to it first.

cheers,
doug.

MVP 2007-2009 - Official Umbraco Trainer for North America - Percipient Studios
drobar
Posted: Wednesday, February 06, 2008 3:01:33 AM

Rank: Umbracoholic

Joined: 9/8/2006
Posts: 1,698
Location: KY, USA
Hi, Finn,

I believe this will do what you want.

Code:

<?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"
    exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes"/>

<xsl:param name="currentPage"/>

<xsl:variable name="documentTypeAlias" select="string('newsItem')"/>
<xsl:variable name="numberOfItems" select="16"/>

<xsl:template match="/">
    <ul>
        <xsl:for-each select="umbraco.library:GetXmlAll()/descendant-or-self::node [
            @nodeTypeAlias=$documentTypeAlias
            and string(data[@alias='showOnFrontpage'] = '1')
            and string(data[@alias='umbracoNaviHide'] != '1')
            ]">
            <xsl:sort select="umbraco.library:FormatDateTime(@createDate, 'yyy.MM.dd')" order="descending"/>
            <xsl:sort select="data[@alias='priority']" order="descending"/>
            <xsl:sort select="@createDate" order="descending"/>

            <xsl:if test="position() &lt;= $numberOfItems">
                <li>
                    <a href="{umbraco.library:NiceUrl(@id)}">
                        <xsl:value-of select="@nodeName"/>
                        <br />
                        <xsl:value-of select="@nodeTypeAlias"/>
                        for <xsl:value-of select="umbraco.library:FormatDateTime(@createDate, 'yyyy.MM.dd H:m')"/>
                        (<xsl:value-of select="data[@alias='priority']"/>)
                    </a>
                </li>
            </xsl:if>
        </xsl:for-each>
    </ul>
</xsl:template>

</xsl:stylesheet>



If you're not overly familiar with XSLT then I'll point you to the GetAllXml() function built into umbraco, which gets all the nodes in your content tree. Then we narrow down the nodes to just those that interest us (they have the right nodeTypeAlias, they are flagged for showOnFrontpage, and they aren't hidden).

Once we've got all the relevant nodes, it is time to sort them. This is where XSLT's syntax is a bit peculiar. You can only sort nodes when doing a for-each loop. That's fine, because we do want to cycle through all the nodes. The odd thing is that the sort command looks like it is "inside" the for-each, but really it is simply "after" the for-each and modifies the for-each itself.

We sort first on the createDate, looking only at the year.month.day to organize the nodes by date. Then we sort by priority to put those flagged as priority at the top of the list of nodes for a given year.month.day. And finally, we sort them by the full createDate which includes the timestamp.

Then it is a simple matter of showing the output in a ul/li list.


I hope this makes sense and works well for you.

cheers,
doug.


MVP 2007-2009 - Official Umbraco Trainer for North America - Percipient Studios
fdo
Posted: Wednesday, February 06, 2008 8:30:18 AM

Rank: Enthusiast

Joined: 6/7/2007
Posts: 18
Location: Copenhagen, Denmark
Douglas, The force is definitely with you!

I’m amazed by the simplicity of your code and your remarks about how it all works and why. It’s easy to understand at manipulate further.

Thank you.
seb
Posted: Wednesday, February 06, 2008 11:34:26 AM

Rank: Devotee

Joined: 1/10/2008
Posts: 75
Location: London
Yep, great example, thanks Doug !
I wish I had seen this GetAllXml function in use before :(
Probably worth to add it in a book/wiki somewhere ?

seb

http://www.be-k.net
bootnumlock
Posted: Wednesday, February 06, 2008 3:47:53 PM

Rank: Fanatic

Joined: 10/9/2006
Posts: 419
yeah, i don't think i have ever used GetXMLAll() before either...hmmmm


Doug, once again... you show your amazing abilities to not only understand, but to teach the knowledge you possess to others...

there really needs to be a permanent spot for you on the umbraco team... minister of information or something :)

bootnumlock - aka bob baty-barr [http://www.baty-barr.com]
Level 1 Certified!
chimnit
Posted: Wednesday, February 06, 2008 4:02:06 PM
Rank: Devotee

Joined: 10/25/2007
Posts: 59
You can also use an XPath expression to retrive all the elements, instead of using the umbraco.library:GetXmlAll() method. I don't know which performs best, or how umbraco is structured, but as far as I know XPath is the fastest way to access data on an XML document.

I have reused Doug's example and only altered the select statement, which should look something like this.

Code:
         <xsl:for-each select="$currentPage/ancestor-or-self::root/descendant-or-self::node [ 
             @nodeTypeAlias=$documentTypeAlias 
             and string(data[@alias='showOnFrontpage'] = '1') 
             and string(data[@alias='umbracoNaviHide'] != '1') 
             ]"> 
             <xsl:sort select="umbraco.library:FormatDateTime(@createDate, 'yyy.MM.dd')" order="descending"/> 
             <xsl:sort select="data[@alias='priority']" order="descending"/> 
             <xsl:sort select="@createDate" order="descending"/> 
   
             <xsl:if test="position() &lt;= $numberOfItems"> 
                 <li> 
                     <a href="{umbraco.library:NiceUrl(@id)}"> 
                         <xsl:value-of select="@nodeName"/> 
                         <br /> 
                         <xsl:value-of select="@nodeTypeAlias"/> 
                         for <xsl:value-of select="umbraco.library:FormatDateTime(@createDate, 'yyyy.MM.dd H:m')"/> 
                         (<xsl:value-of select="data[@alias='priority']"/>) 
                     </a> 
                 </li> 
             </xsl:if> 
         </xsl:for-each>


You can read more about this on w3schools.com.

Hope you can use it :o)
Cheers,
Kim
Users browsing this topic
Guest


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.