The use of XSLT in Sitecore have been around since Sitecore 4. XSLT’s are fast to write and easy to deploy: All you need to update an XSLT is to copy a new file to your web server.
The nature of an XSLT is to convert XML into other XML (XHTML for example). Sitecore can serialize its content and structure into XML, so using XSLT’s to create the (X)HTML for your website seems to be the correct solution.
However, as the complexity of our web solutions grow, so does our XSLT’s. I have seen XSLT’s with 100′s of lines in them, calling sub templates and even including other XSLT’s. XSLT’s with more than a few lines in them are near-impossible to maintain and leads to mistakes like the “comparing a complete tree structure” error:
<xsl:for-each select="$items[sc:fld('Navigation_Show',.) = '1']">
// This is wrong: I compare
// the complete structure with the complete structure
<xsl:if test=". = $sc_item">
Do something
<xsl:if>
// This is better: Comparing on Sitecore GUIDS
<xsl:if test="@id = $sc_item/@id">
Do something
<xsl:if>
</xsl:for-each>
When including other XSLT’s into a “base” XSLT you start making a yarn ball of code that only you will understand.
One of the primary reasons to choose XSLT’s was that the sc: controls (sc:text, sc:html, …) were the only controls to support inline editing (web edit). However, this obstacle has been removed, as Sitecore has introduced the sc:FieldRenderer webcontrol to be used in User Controls.
<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %>
This control renders the field in web edit mode as well. The FieldRenderer is simple to use:
<sc:FieldRenderer FieldName="Title" runat="server" />
The FieldRenderer is not the only reason you should switch to UserControls.
When sticking to XSLT’s you miss out on the huge Sitecore API that will help you do almost any task with just a few lines of code.
UserControls can be as easy to deploy as XSLT’s (if you stick all of your code into the .ascx file), and you still have access to a code-behind file where you can code all of your business logic as needed.
Now lets see other examples. Here is a simple sub-menu, listing all items below the current item:
<%@ Control Language="c#" AutoEventWireup="true" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %>
<script runat="server">
void Page_Load(object sender, System.EventArgs e) {
DataBind();
}
IEnumerable<Sitecore.Data.Items.Item> SubItems
{
get { return Sitecore.Context.Item.Children; }
}
</script>
<asp:Repeater ID="repSubItems" runat="server" DataSource="<%# SubItems %>">
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<a href="<%# Sitecore.Links.LinkManager.GetItemUrl(Container.DataItem as Sitecore.Data.Items.Item) %>">
<sc:FieldRenderer FieldName="Title" runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
</a>
</div>
</ItemTemplate>
<FooterTemplate>
</FooterTemplate>
</asp:Repeater>
Here is a breadcrumb. The pattern is almost as the example above:
<%@ Control Language="c#" AutoEventWireup="true" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %><script runat="server">
void Page_Load(object sender, System.EventArgs e) {
DataBind();
}
IEnumerable<Sitecore.Data.Items.Item> Breadcrumb
{
get
{
List<Sitecore.Data.Items.Item> itemsInPath = new List<Sitecore.Data.Items.Item>();
Sitecore.Data.Items.Item currentItem = Sitecore.Context.Item;
Response.Write(currentItem.Key);
while (currentItem.Key != "content")
{
itemsInPath.Add(currentItem);
currentItem = currentItem.Parent;
}
itemsInPath.Reverse();
return itemsInPath;
}
}
</script>
<asp:Repeater ID="repBreadcrumb" DataSource="<%# Breadcrumb %>" runat="server">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<a href="<%# Sitecore.Links.LinkManager.GetItemUrl(Container.DataItem as Sitecore.Data.Items.Item) %>">
<sc:FieldRenderer ID="FieldRenderer1" FieldName="Title" runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
</a>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
So do yourself a favor. Take a look at the new possibilities in using UserControls, and consider the use of XSLT’s very carefully before you implement them.

January 26, 2011 at 5:40 pm
Good points. Also it’s really a hassle to work with xslt files since the language itself is not a programming language it’s a rendering language. You’ll spend a lot of time building something in the obscure language only to find out that you can’t do what you’re trying to do. Variables can be set but not updated and it was never intended to do programming kinds of task. I realize people have concerns about load times and it is faster since there’s no binaries to run but I’ve seen large scale projects with lots of visitors run without any xsl and still have good response time. Also do the next developer on the project a favor and don’t use xslt so when they have to extend your project they’re not forced to rebuild everything. This also applies to all those people who build on Umbraco.
January 27, 2011 at 12:20 am
hi Brian,
Great post and great points about why to be careful when choosing to use XSL renderings.
I admit I’m guilty of having used XSL renderings in my first few Sitecore implementations but quickly realized that maintenance was a nightmare.
One other point I’d add in favor of using UserControls or WebControls is debugging. It’s much easier to be able to step into the code for a rendering as opposed to trying to track down a rendering issue in XSLT.
Cheers!
adam
January 30, 2011 at 4:56 pm
Chapter 5 of the Presentation Component Reference has a section about the advantages & disadvantages of the various rendering technologies:
http://sdn.sitecore.net/Reference/Sitecore%206/Presentation%20Component%20Reference.aspx
Another reason to use web controls specifically is that you can define your own caching criteria by implementing the GetCachingID() method.
February 22, 2011 at 6:42 pm
Hi Brian,
I’m trying out your code for the sub-menu and get this compilation error:
CS0266: Cannot implicitly convert type ‘Sitecore.Collections.ChildList’ to ‘System.Collections.Generic.IEnumerable’. An explicit conversion exists (are you missing a cast?)
What do you think might be going on? I was able to get your breadcrumb to work.
Thanks!
Chris
February 23, 2011 at 7:18 am
Hmm, it must be the Sitecore version. I probably used one of the latest Sitecore 6.2.? or even 6.3.?
In the later versions of ChildList, it implements IEnumerable, ICollection and IEnumerable which makes the cast possible.
February 28, 2011 at 12:01 pm
[...] Posts Using UserControls instead of XSLT in Sitecore projectsMultiple languages in SitecoreGSA (Google Search Appliance) Suggest using C# and jQuerySetting up [...]
March 13, 2011 at 11:15 am
[...] pipeline is used by the sc:FieldRenderer web control when you render fields from web controls and user controls (.aspx and .ascx files). If [...]
June 21, 2011 at 8:04 am
[...] Find out more… [...]
August 3, 2011 at 10:48 am
[...] With Sitecore 5 and Sitecore 6, XSLT’s are becomming deprecated, as it is getting easier and easier to create the same using UserControls. [...]
November 28, 2011 at 1:04 pm
[...] Editable from the beginning. Although I would recommend that you rewrite your website using the sc:FieldRenderer. LD_AddCustomAttr("AdOpt", "1"); LD_AddCustomAttr("Origin", "other"); [...]
February 10, 2012 at 11:43 am
[...] place I would look for performance issues. Most performance issues comes from poor XSLT design (which is why I quit using XSLT’s). Other issues revolve around selecting too many items at once (remember to use the Lucene index). [...]