21

XSLT newbie question: Please fill in the blank in the C# code fragment below:

public static string TransformXMLToHTML(string inputXml, string xsltString) {
  // insert code here to apply the transform specified by xsltString to inputXml 
  // and return the resultant HTML string.
  // You may assume that the xslt output type is HTML.
}

Thanks!

Shaul Behr
  • 36,951
  • 69
  • 249
  • 387

2 Answers2

45

How about:

public static string TransformXMLToHTML(string inputXml, string xsltString)
{
    XslCompiledTransform transform = new XslCompiledTransform();
    using(XmlReader reader = XmlReader.Create(new StringReader(xsltString))) {
        transform.Load(reader);
    }
    StringWriter results = new StringWriter();
    using(XmlReader reader = XmlReader.Create(new StringReader(inputXml))) {
        transform.Transform(reader, null, results);
    }
    return results.ToString();
}

Note that ideally you would cache and re-use the XslCompiledTransform - or perhaps use XslTransform instead (it is marked as deprecated, though).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Marc, you are a prince among men. :) – Shaul Behr Nov 22 '09 at 10:08
  • Very neat and simple. – Chris Aug 28 '13 at 09:23
  • 2
    well it can get simpler than this. All those XML readers can be replaced with actual location of the files like: XslCompiledTransform transform = new XslCompiledTransform("file://"+xsltString); Also transform has a version that you can pass the location of the file using that "file://" + inputXml trick ;) – tecfield Nov 21 '14 at 15:46
4

Just for fun, a slightly less elegant version that implements the caching suggested by Marc:

    public static string TransformXMLToHTML(string inputXml, string xsltString)
    {
        XslCompiledTransform transform = GetAndCacheTransform(xsltString);
        StringWriter results = new StringWriter();
        using (XmlReader reader = XmlReader.Create(new StringReader(inputXml)))
        {
            transform.Transform(reader, null, results);
        }
        return results.ToString();
    }

    private static Dictionary<String, XslCompiledTransform> cachedTransforms = new Dictionary<string, XslCompiledTransform>();
    private static XslCompiledTransform GetAndCacheTransform(String xslt)
    {
        XslCompiledTransform transform;
        if (!cachedTransforms.TryGetValue(xslt, out transform))
        {
            transform = new XslCompiledTransform();
            using (XmlReader reader = XmlReader.Create(new StringReader(xslt)))
            {
                transform.Load(reader);
            }
            cachedTransforms.Add(xslt, transform);
        }
        return transform;
    }
Dathan
  • 7,266
  • 3
  • 27
  • 46
  • You'd have to worry about thread safety / synchronization around the dictionary, but something along those lines, yes. – Marc Gravell Nov 22 '09 at 11:04
  • And it occurs to me that it might be worthwhile to hash the xsltString and use that hash as a key instead. Some transforms can get pretty big - no reason to incur the extra memory penalty storing it in compiled form in the XslCompiledTransform and again as the key. – Dathan Nov 24 '09 at 02:30