Use code blocks to extend your BizTalk custom XSLT maps
Update 2010-04-13
Grant Samuels commented and made me aware of the fact that inline scripts might in some cases cause memory leaks. He has some further information here and you’ll find a kb-article here.
I’ve posted a few times before on how powerful I think it is in complex mapping to be able to replace the BizTalk Mapper with a custom XSLT script (here’s how to). The BizTalk Mapper is nice and productive in simpler scenarios but in my experience it break down in more complex ones and maintaining a good overview is hard. I’m however looking forward to the new version of the tool in BizTalk 2010 – but until then I’m using custom XSLT when things gets complicated.
Custom XSLT however lacks a few things once has gotten used to have – such as scripting blocks, clever functoids etc. In some previously post (here and here) I’ve talked about using EXSLT as a way to extend the capabilities of custom XSLT when used in BizTalk.
Bye, bye external libraries – heeeello inline scripts
Another way to achieve much of the same functionality even easier is to use embedded scripting that’s supported by the XslTransform class. Using a script block in XSLT is easy and is also the way the BizTalk Mapper makes it possible to include C# snippets right into your maps.
Have a look at the following XSLT sample:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:code="http://richardhallgren.com/Sample/XsltCode"
exclude-result-prefixes="msxsl code"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<Test>
<UniqueNumber>
<xsl:value-of select="code:GetUniqueId()" />
</UniqueNumber>
<SpecialDateFormat>
<xsl:value-of select="code:GetInternationalDateFormat('11/16/2003')" />
</SpecialDateFormat>
<IncludesBizTalk>
<xsl:value-of select="code:IncludesSpecialWord('This is a text with BizTalk in it', 'BizTalk')" />
</IncludesBizTalk>
</Test>
</xsl:template>
<msxsl:script language="CSharp" implements-prefix="code">
//Gets a unique id based on a guid
public string GetUniqueId()
{
return Guid.NewGuid().ToString();
}
//Formats US based dates to standard international
public string GetInternationalDateFormat(String date)
{
return DateTime.Parse(date, new System.Globalization.CultureInfo("en-US")).ToString("yyyy-MM-dd");
}
//Use regular expression to look for a pattern in a string
public bool IncludesSpecialWord(String s, String pattern)
{
Regex rx = new Regex(pattern);
return rx.Match(s).Success;
}
</msxsl:script>
</xsl:stylesheet>
All one has to do is to define a code block, reference the xml-namespace used and start coding! Say goodbye to all those external library dlls!
It’s possible to use a few core namespaces without the full .NET namespace path but all namespaces are available as long as they are fully qualified. MSDN has a great page with all the details here.
There's 7 Comments So Far
April 12th, 2010 at 6:26 pm
Yeay, for once you write about something that I can relate to and not just hardcore biztalk stuff
Really cool stuff, seems to (amongst other things) have great potential to improve readability in large/complex transformations. It would be interesting to know a bit more about the security implications. Under what credentials will the code execute? Is there any restrictions while the code is running (CAS, trust, etc)?
April 13th, 2010 at 9:49 am
Will this cause memory leakage as described:
http://linderalex.blogspot.com/2008/06/memory-leak-using-biztalk-mapper.html
http://support.microsoft.com/kb/918643
Inline script seems to be the culprit in these scenarios?
April 15th, 2010 at 12:33 am
Hi Richard
Would be interested to hear your view on this….
In general I tend to try to use external assemblies in preference to inline scripts as my default approach. The single most important reasons in my opinion for doing this is that developers dont effectively cover the unit testing of the helper functions when they are implemented as inline scripts. When they are in a helper class I get code coverage analysis to ensure they are tested properly and can implement things like check in policies to ensure they are doing their job.
I think one of the biggest causes of bugs in maps I come across on our projects is poor code in inline scripts which has not been tested.
Just wondered if you had a view on this or had covered this some other way
Cheers
Mike
April 15th, 2010 at 6:04 am
@Mike: First, thanks for your comment.
I also think there is a very relevant point in your comment. When using longer methods with more complex logic we still usally try and do this in an external assembly. Partly is has to do with quality and testing as you mention. But it’s also much easier to develop and be more productive in pure code than in a script.
However when that’s said I really like the option to use online script for easier and small chunks of code such as string, date manupulation and so on. These small methods usally goes untested and usally isn’t a problem.
May 10th, 2010 at 7:41 am
I have a feeling that C# inline scripts can be compared to using vendor specific stored procedures in SQL, mixing HTML and php, etc. instead of separating structure and logic (well, xslt can be seen as logic perhaps
but you get the idea).
Bascially you lose portability of the otherwise portable XSLT in case you want to move to another platform in the future. Like migrating off a Oracle database needs conversion of the stored procedures, etc.
I realize that inline scripting (and external libs) is a cool and powerful tool, but is there some other way? Is XSLT expressive enough to implement such functions self-contained, i.e. opening up the possibility of a standard library of common functions?
May 10th, 2010 at 7:53 am
@Stefan: I see you point. I do however think that XSLT 1.0 lacks so much functionality today that one has to find some way of extending it to solve small easy tasks without 100 lines of xslt
. EXSLT could be anotherway as I describe here. I don’t however feel that it gives you more portability and is vendor more agnostic solution …
August 4th, 2010 at 4:36 am
Hi Richard,
Thanks for the excellent article on the xslt usage within Biztalk and the links to the msdn articles.
I was hoping you would be able to offer your opinion on the following scenario: One of the goals of an app I am currently writing is allowing external systems to provide some data to us in our format, however our format would still allow flexibility for “lookUps”.
Sometimes this might be via it’s Code (string), Name (string), Code and Category (strings).
When these lookUps are performed we would expect the lookUp element to be replaced with an Id element in the output.
We would use the compiled transform in a singleton pattern to ensure the script assembly is loaded only once into the appDomain.
1. The database look up code is extremely quick and efficient outside of xslt, do you think this would cause huge performance issues when running inside of an xsl script block?
2. Is there a way to have the xslt use the current assemblies in the appDomain that have already been configured for use, i.e. to use the dependency injection framework and other nice tools?
Thanks for your time
Pete
Share your thoughts, leave a comment!