Monday, July 4, 2011

Transforming XML using BizTalk Mapper generated XSLT

If I have to write XSLT I try and make use of the BizTalk Mapper because it can generate XSLT in a fraction of the time.  It also supplies a test harness so you can use an input file to test out your map.
You can add functoids to your map and I make use of the Scripting functoid so that I can write inline C# script.  Here is an example of a function that takes a string source element and will truncate it if it is longer than the string length the target element can handle.  It writes out an Information message to the event log if the maximum length is exceeded.
The function takes two extra parameters apart from the source element:  the name of the source element and the maximum length.  Add them by clicking on the ellipses next to Configure Functoid Inputs.

Here is the inline C# script.
public string Transform(string param1, string fieldname, int32 maxlength)
{
       if (param1.Length > maxlength)
      {
             System.Diagnostics.EventLog.WriteEntry("Transformation", fieldname + " in excess of " +   maxlength.ToString() + " chars, truncating", System.Diagnostics.EventLogEntryType.Warning);
             return param1.Substring(0, 20);
      }
      else
     {
             return param1;
      }
}

What BizTalk does is to write this out as a function at the botton of the XSLT.  To produce the XSLT, use Validate Map and then navigate to where the output window has written the file. 

Now I struggled a bit to get this XSLT to work until I finally found the answer was to use an XPathDocument instead of an XmlDocument. That's it. A transformation using the output from the BizTalk Mapper.  Deep, deep joy. 

Add the following using statements
using System.Xml;
using System.Xml.Xpath;
using System.Xml.Xslt;

// Transforms an XML document
// using an XSLT generated by BizTalk
// note use of XPathDocument
private XmlDocument Transform()
{

     XslCompiledTransform xslt = new XslCompiledTransform();
     // load the xslt
     xslt.Load(@"C:\Projects\Import\MySchema.xsl", new XsltSettings(false, true), new XmlUrlResolver());
     string filePathName = @"C:\Projects\Import\MyXML.xml";
     //Load the XML data file.
     XPathDocument doc1 = new XPathDocument(filePathName);
     // create a memory stream
     MemoryStream ms = new MemoryStream();
    //Create an XmlTextWriter to write to the memory stream
    XmlTextWriter writer = new XmlTextWriter(ms, Encoding.Unicode);
    writer.Formatting = Formatting.Indented;

    //Transform the file.
    xslt.Transform(doc1, null, writer, null);
    ms.Seek(0, SeekOrigin.Begin);  // ** UPDATE changed from ms.Position=0 ****//
     if (ms.Length == 0)
    {
           Exception ex = new Exception ("Transform error , output is null");
           throw ex;
    }
    // load the memory stream into a XML document
    XmlDocument output = new XmlDocument();
    output.Load(ms);
    writer.Close();
    return output;
}