Day 5: XslCompiledTransform, I miss you.

Oh man, Day 5? I'm really bad at this. But hey, I was up front that I wouldn't actually be posting on a daily basis.

It's pretty hard to write an application that doesn't touch XML in some way these days. A while ago, I found myself in several situations where I was wishing I could run an XML document through an XSLT before processing it. As a workaround, I'd load the document into an XmlDocument and do the transformation programmatically.

That's obviously a bit of a bitch, so after some thorough digging, I found that Windows Mobile 6+ ships with the unmanaged MSXML API, and that you can create wrappers for these COM objects using the MIDL compiler and adding a reference to the type library file (TLB).

My deterrence from using this is that for everything I write I need to remember to add the COM wrapper, Interop.MSXML2.dll, to my CAB setup files. This isn't a huge deal when it's a single file, obviously. But updating my setup projects every time I add a COM wrapper is very tedious.

Normally, I could just embed that DLL as a resource in my assembly, and call Assembly.Load on the resource stream. However, .NET CF does not have that particular overload of Assembly.Load. So my horrible solution: embed it as a resource, and when the static constructor on XslCompiledTransform is called, write that file out to the current directory and load it:


static XslCompiledTransform()
{
    try
    {
        Assembly.LoadFrom("Interop.MSXML2.dll");
    }
    catch (Exception)
    {
        string cwd = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        using (FileStream fs = new FileStream(Path.Combine(cwd, "Interop.MSXML2.dll"), FileMode.Create))
        {
            using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("CompactFrameworkExtensions.Interop.MSXML2.dll"))
            {
                fs.Copy(stream);
            }
        }

    }
}

Note: This may cause "dirty" uninstallation issues.

Oh, that reminds me, the "fs.Copy(stream)" is a handy extension method that allows you to copy the contents of a stream into another.

Usage is pretty straightforward:

class Program
{
    static void Main(string[] args)
    {
        XslCompiledTransform trans = new XslCompiledTransform();
        trans.LoadString(Resource1.XSL);
        string ret = trans.TransformString(Resource1.XML);
    }
}

Resource1.XML and Resource1.XSL are simply strings that contain the documents.

Click here for the full source to XslCompiledTransform and some other handy extension methods.

0 comments: