Using XSLT in your SharePoint web part

I've been doing a lot of content management work with SharePoint lately, which means a lot of the same functionality but always a different look and feel.  XSLT is one of the main pillars of SharePoint development, and if you haven't been using it or haven't been using it extensively than you are doing yourself a huge disservice.  Every time I create a SharePoint web part or control I always make the presentation use an XSL style sheet and allow that style sheet to be configured through a property.  This is very similar to how the Content Query WebPart works, just most people end up using the default styles that come out of the box.  This has saved me many times from redeveloping a web part or control just because the HTML or styling isn't just how the customer wants it.  It is also a great way to get HTML markup out of your code, which just makes the code extremely hard to read.  I'm going to show you how to use XSLT in all of your web parts from now on with a few simple examples.  Here it goes....

 

The first example is when you are using a response from a datasource that returns XML already.  The example I'm going to use is a Yahoo RSS feed.  I know that for this you could simply use the RSS web part and modify that XSL but this is for demonstration purposes.  You might have a XML Document for a data source.  The first thing we need to do is get the XML.  I did this as an Async method so it might be a little different if you aren't using Async methods.

 

 IAsyncResult BeginGetIndustryNews(Object sender, EventArgs e, AsyncCallback cb, object state)
    {
        industrynewsReq = (HttpWebRequest)WebRequest.Create(industryNewsUrl);

        industrynewsReq.Method = "GET";

        industrynewsReq.Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy();

        industryNewsResult = industrynewsReq.BeginGetResponse(cb, industrynewsReq);

        return industryNewsResult;
    }

    void EndGetIndustryNews(IAsyncResult asyncResult)

    {

        if (industryNewsResult != null)

        {

            WebResponse response2 = (WebResponse)industrynewsReq.EndGetResponse(asyncResult);

            Stream streamResponse2 = response2.GetResponseStream();

            industryNewsHtml.Text = GetTransformResults(industryNewsXsl, streamResponse2);

            response2.Close();

            streamResponse2.Close();

        }

    }

private string GetTransformResults(string xslLink, Stream responseStream)

    {

        XmlUrlResolver resolver = new XmlUrlResolver();

        resolver.Credentials = CredentialCache.DefaultCredentials;

        XmlTextReader stylesheet = new XmlTextReader(SPContext.Current.Site.Url + xslLink);

        stylesheet.XmlResolver = resolver;

        XslCompiledTransform transform = new XslCompiledTransform();

        transform.Load(stylesheet);

        StringBuilder sb = new StringBuilder();

        TextWriter writer = new StringWriter(sb);

        using (XmlReader reader = new XmlTextReader(responseStream))

        {

            XmlTextWriter results = new XmlTextWriter(writer);

            transform.Transform(reader, results);

            reader.Close();

        }

        return sb.ToString();

    }

If you haven't figured it out already the important method here is the "GetTransformResults".  This is the method that takes the input stream and applies the XSL to it.  In this method I create an XmlUrlResolver in order to use the current users credentials when accessing the XSL stylesheet.  I then use a XmlTextReader to get the stylesheet.  I then pass the XslCompiledTransform the XmlTextReader of the style sheet and call the transform method, writing the results to a StringBuilder.  When I return this StringBuilder to the calling method what I am returning is a string of HTML that was created by transforming the XML data with the XSL transform.  When I get the result in the EndGetIndustryNews method I set the Text property of the IndustryNewsHTML control, which is simply a literal control on the page.  That's it!  You now have a reusable control that you can change the look and feel of very easily without changing any code.  In case you are wondering industryNewsXsl is a property on this control that can be set to any Xsl stylesheet in the site collection.  To keep things consistent I usually place mine in the /style library/xsl style sheets folder.

This is all great but what if you have an object that contains the data that you want to transform?  Surprisingly this is even easier.  Simply use the built in XmlSerializer to get the XML representation of your object like so.

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Newsletter));

MemoryStream memoryStream = new MemoryStream();
serializer.Serialize(memoryStream, newsletter);
memoryStream.Position = 0;

newsHtml.Text = GetTransformResults(newsXsl, memoryStream);

In this case you might have a little trouble if you don't know exactly what the XML looks like that is coming out of the serializer.  In case you want to get a look at the raw XML (which you probably will) you can use the style sheet below which will output in a textarea the bare XML.

 <xsl:stylesheet version="1.0" exclude-result-prefixes="x d xsl msxsl cmswrt" xmlns:x="https://www.w3.org/2001/XMLSchema" xmlns:d="https://schemas.microsoft.com/sharepoint/dsp" xmlns:cmswrt="https://schemas.microsoft.com/WebParts/v3/Publishing/runtime" xmlns:xsl="https://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">


<xsl:template match="/">
    <textarea rows="20" cols="100">
        <xsl:apply-templates/>
    </textarea>
    
</xsl:template>
<xsl:template match="node()|@*">
    <!-- Copy the current node -->
        <xsl:copy>
        <!-- Including any child nodes it has and any attributes -->
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

That's all there is to this really.  Hopefully this will help you in writing all your web parts and controls in SharePoint to take advantage of XSL!