Converting Sitecore items to XML to use in XSLT renderings

Published by on
Tags:

Sometimes you want to retrieve an item or collection of items using C# and then pass these items to an XSLT rendering. The advantage of this is that you get the processing power of C# with the simple layout and Sitecore XSLT controls of a rendering. To do this the following methods and extension methods should help. The interesting stuff, the code:

        public static XPathNodeIterator ToXml(this Item item)
        {
            return ToXml(new Item[] { item });
        }

        public static XPathNodeIterator ToXml(this Item[] items)
        {
            return ConvertToXml(items);
        }

        private static XPathNodeIterator ConvertToXml (Item [] items)
        {                         
            var packet = new Packet("values", new string[0]);
            foreach (Item item  in items)
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(item.GetOuterXml(false));
                packet.AddXml(doc);
            }            
            return GetChildIterator(packet);                
        }

        private static XPathNodeIterator GetChildIterator(Packet packet)
        {
            XPathNavigator xpathNavigator = packet.XmlDocument.CreateNavigator();
            if (xpathNavigator == null)
            {
                return null;
            }
            xpathNavigator.MoveToRoot();
            xpathNavigator.MoveToFirstChild();
            return xpathNavigator.SelectChildren(XPathNodeType.Element);
        }

Using the Packet class which exists in the Sitecore.Xml namespace we can load our item/items into it and then pass the whole lot back to the XSLT rendering by creating an XPathNodeIterator from the packet . The extension methods allow us to more easily call the method. To call the methods:

        public static XPathNodeIterator doQuery(string query)
        {
            Item[] results = Sitecore.Context.Database.SelectItems(query);
            return results.ToXml();
        }

Or


        public static XPathNodeIterator doQuery(string query)
        {
            Item result = Sitecore.Context.Database.SelectSingleItem(query);
            return result.ToXml();
        }	 

Within our XSLT we can then use it like so:

    <xsl:variable select="eic:doQuery($query)" name="results" />
    <xsl:for-each select="$results">      
        <sc:text field="Title" />   
    </xsl:for-each>

I can iterate over the items as I would normally and can call of the standard Sitecore XSLT controls

Sitecore Sublayout Parameters

Published by on
Tags:

Ok close on the heels of my previous post comes another useful extension method (I might be getting carried away with these). This extension method is to help those of you developing in Sitecore. I came up against the problem today of needing to extract the parameters associated to sub-layout.

For those unclear on parameters and sub-layout these can be found by going to a template in Sitecore (I am assuming Sitecore 5.3), click on the Presentation tab and then click Layout. Click the Edit button beneath a layout with a sub-layout. Click on the Sub-layout and in the new popup select the parameters tag. You should see the following screen:

Parameters are useful because they allow you to pass in specific values to a layout.Ok so the code I originally looked at was taken from that given by Sitecore:

   25             Database db = Sitecore.Context.Database;

   26             Item item = db.Items["/sitecore/templates/SC Printers/Section"];

   27             string rend = item.Fields["__renderings"].Value;

   28             LayoutDefinition layout = LayoutDefinition.Parse(rend);

   29             DeviceItem dev = Sitecore.Context.Device;

   30             DeviceDefinition device = layout.GetDevice(dev.ID.ToString());

   31             Item mySublayout = db.Items["/sitecore/layout/Sublayouts/Two columns"];

   32             RenderingDefinition rendering = device.GetRendering(mySublayout.ID.ToString());

   33             Response.Write("Parameters: " + rendering.Parameters);

   34             Response.Write("<br/>");

   35             Response.Write("DataSource: " + rendering.Datasource);

However there are several problems with this code. It assumes that the item has a rendering specified and not inherited from a template and it will also fail if the device that Sitecore picks up has not associated layout; for example if I specify a device for Firefox users but then don't specify and layouts for it it shoud fall back to the default device, but this code doesn't. Another problem with the code is that it returns the list of parameters as a string, if you have more than one parameter they are all concantinated into one long string. I wanted to seperate these out so that they were more usable. The solution is the following code:

   21         private static readonly string _renderingField = "__renderings";

   22 

   23         public static KeyValuePair<string,string> [] GetSubLayoutParameters(this Item item, Guid subLayoutId)

   24         {         

   25 

   26             string rend = item.Fields[_renderingField].Value;

   27             //if there are no renderings on the item use the template render

   28             if (rend.IsNullOrEmpty())

   29             {

   30                 rend = item.Fields[_renderingField].InheritedValue;

   31             }

   32             LayoutDefinition layout = LayoutDefinition.Parse(rend);

   33             DeviceItem dev = Sitecore.Context.Device;

   34             DeviceDefinition device;           

   35 

   36             //get the current device

   37             device = layout.GetDevice(dev.ID.ToString());

   38             //if the current device has no layout fail back

   39             if (device.Layout == null)

   40             {

   41                 dev = dev.FallbackDevice;

   42                 device = layout.GetDevice(dev.ID.ToString());

   43             }

   44 

   45             //get the rendering for the device

   46             RenderingDefinition rendering = device.GetRendering(new ID(subLayoutId).ToString());

   47 

   48             //create a list of key values

   49             List<KeyValuePair<string, string>> parameters = new List<KeyValuePair<string, string>>();

   50             string [] pairs = rendering.Parameters.Split('&');

   51 

   52             foreach(string pair in pairs){

   53                 if(!pair.IsNullOrEmpty()){

   54                     string [] vals = pair.Split('=');

   55                     if(vals.Count() == 2){

   56                         parameters.Add(new KeyValuePair<string,string>(vals[0], vals[1]));

   57                     }

   58                 }

   59             }

   60 

   61             return parameters.ToArray();              

   62 

   63         }

You will notice that I have used a couple of the extension methods from my Extension Method - Part 1 post. I hope this makes getting parameters a little easier for everyone out there.

Further reading: How to find the currently executing sublayout in Sitecore

Useful Extensions Methods - Part 1

Published by on
Tags:

I am going to start blogging extension methods that I think are useful. The onesI have detailed below are very simple but I think they make code more readable andquicker to write.

The first is to do with passing in objects to have them formatted in the outputtext. The standard way to do this is:

   12        string name = "mike";

   13        int age = 25;

   14        string text = "Hello{0}, You are {1} years old";

   15 

   16        Console.WriteLine(string.Format(text,name, age));

I don't like this, why should I have to use a static method on the string type?Why can't this be a method on the instance of the string? So I created an extensionfunction to do this:

   26        public staticstring Params(thisstring text, paramsobject[] args)

   27        {

   28            return string.Format(text, args);

   29        }

And now I can do the same as above but swap out line 16 for:

   18        Console.WriteLine(text.Params(name, age));

The second one I find useful is for casting objects to a different types. Take forexample the following code example where I have an interface and a concrete class:

   38     public interfaceICalc

   39     {

   40        int Add(inta, int b);

   41     }

   42 

   43     public class Calc : ICalc

   44     {

   45        public stringCalcName { get { return"My Calc"; } }

   46 

   47        #region ICalc Members

   48 

   49        public intAdd(int a, intb)

   50        {

   51            return a + b;

   52        }

   53 

   54        #endregion

   55     }

 

I create an instance of the concrete class like so:

 

   20            ICalc myCalc = new Calc();

 

Say for some reason (there could be many) I need to access the CalcName propertythat is not defined in the interface, this means I need to cast my current instanceto the concrete type. This would normally be done like so:

 

   23            ((Calc)myCalc).CalcName;

 

This to me is not a nice solution. So I created this extension function:

 

   35         public static T AsType<T>(this object obj)

   36         {

   37             return (T) obj;

   38         }

 

Now I can do the same as above but like so:

 

   21             myCalc.AsType<Calc>().CalcName;

 The joy of extension method is that even simple ones can make coding quicker and easier to read. Let me know if you have some useful extension functions that I could make use of.

Sitecore Sheer XAML Applications - Part 1

Published by on
Tags:
This week I have been working on a new Sheer XAML application for Sitecore. The ability to add applications to the Sitecore client is a powerful tool,  however I noticed that there isn’t a huge amount of information on how to create these applications and this probably puts off a lot of developers. I hope to document some useful bit’s and pieces over the next few weeks but I thought I would start with a simple extension function.

If you are dynamically changing the UI of the Sheer application through code you need to send the new HTML to the browser. All the Sitecore controls descend form Sitecore.Web.UI.WebControl. This allows us to create a simple extension function that can be used by any of the Sitecore controls to send back their new HTML output.

   24     public static void RefreshHtml(this Sitecore.Web.UI.WebControl control)

   25     {

   26         Sitecore.Context.ClientPage.ClientResponse.SetOuterHtml(control.ID, control);

   27     }


Then to simply update any control in your XAML application you simply call the refresh method:

   15     Sitecore.Web.UI.HtmlControls.Listview view = new Sitecore.Web.UI.HtmlControls.Listview();

   16     view.RefreshHtml();

 

All blogs tagged with 'extension methods'

Projects

Have you read?

SharePoint SPSecurity.RunWithElevatedPermissions



Blogs by date