This is the 2nd part of the series “Getting started with XSL extensions”. In this part you will learn to use parameters and get some tips on what to avoid, when using XSL extensions.
Using parameters:
It is pretty simple to parse parameters from your XSLT to your XSL extension. However you need to be careful with the types. There are no compile time errors, when parsing the wrong types as parameters or the return type for that matter. Instead you will get a runtime error in your XSLT.
You can pass a simple string to your XSL extension by adding a parameter to your extension method:
namespace LearnSitecore.Examples.XSL
{
public class MyXSLExtension
{
public string StringParameter(string s)
{
return "!!!" + s + "!!!";
}
}
}
This can be called like this:
< xsl:value-of select = "ls:StringParameter('teststring')"/>
This will return “!!!teststring!!!”. You can also use other types such as integer. XSL doesn’t have the type system of C#, but the type is parsed in correctly anyway. Take a look at the following method:
namespace LearnSitecore.Examples.XSL
{
public class MyXSLExtension
{
public int Add(int a, int b)
{
return a+b;
}
}
}
This can be called with string values like this:
< xsl:value-of select = "ls:Add('1','41')"/>
This will correctly return 42 even though it is strings, which are parsed in. However if you parse in a string that cannot be converted to an integer, it will throw a runtime exception. Therefore you need to be careful when parsing in values from Sitecore fields, which don’t use validation to ensure the type. Luckily Sitecore provides an integer field in Sitecore 6. Use this whenever you need this type.
One thing you often want to parse in is a Sitecore item. But when you parse an item in to you extension, it won’t be converted to an Item but an XPathNodeIterator. In the same matter you can’t return a Sitecore item. So you need a helper method, which converts items between an XPathNodeIterator and a Sitecore Item.
Imagine the hypothetical situation where you want a method, which returns the second child of an item. You don’t want to iterate over all the children in your XSLT, so you create an extension. You need to pass in the root as a parameter and return the second child and create the method like this:
public XPathNodeIterator GetSecondChild(XPathNodeIterator root)
{
Item rootItem = ItemFromXPathNodeIterator(root);
return XPathNodeIteratorFromItem(rootItem.Children[1]);
}
Here the methods ItemFromXPathNodeIterator and XPathNodeIteratorFromItem do the work of converting the type. They look like this:¨
private Item ItemFromXPathNodeIterator(XPathNodeIterator root)
{
if (!root.MoveNext())
return null;
//get id from current node
string itemID = root.Current.GetAttribute("id", string.Empty);
//get sc item
return Sitecore.Context.Database.Items[itemID];
}
The method gets the item id from the XML and then looks it up in the current context database.
private XPathNodeIterator XPathNodeIteratorFromItem(Item item)
{
if (item == null)
return null;
// Use the Sitecore Factory to generate a ItemNavigator and select the root
Sitecore.Configuration.Factory.CreateItemNavigator(item).Select(".");
}
The method uses Sitecore’s API to get a XPathNodeIterator from an item.
The above code works fine and you’re doing fine. But suddenly your boss comes complaining. Some sides return a nasty XSL error. You realize that you haven’t validated your input. What if the root node doesn’t have two children? You will then get an index out of bound exception. Now XSLT’s doesn’t understand a null reference so you can’t return null. Instead you need to return an empty XPathNodeIterator like this:
public XPathNodeIterator GetSecondChild(XPathNodeIterator root)
{
Item rootItem = ItemFromXPathNodeIterator(root);
if (rootItem == null)
return EmptyXPathNodeIterator();
if(rootItem.Children.Count < 2)
return EmptyXPathNodeIterator();
return XPathNodeIteratorFromItem(rootItem.Children[1]);
}
Where the EmptyXPathNodeIterator() looks like this:
private XPathNodeIterator EmptyXPathNodeIterator()
{
XmlDocument doc = new XmlDocument();
emptyNavigator = doc.CreateNavigator();
return emptyNavigator.Select("*");
}
Now your method should be robust.
Well that’s it. You have now learned to create XSL extensions and use parameters… So congratulations! :)