How the extend a custom Xslt in BizTalk using EXSLT and the Mvp.Xml project
Lately I've been using custom Xslt more and more instead of the BizTalk mapping tool. I still use the mapping tool in easy scenarios when I just need to do some straight mapping or maybe even when I need to concatenate some fields, but as soon as I need to to some looping, grouping, calculations etc I've made a promise to myself to use custom Xslt!
I find custom Xslt so much easier in more complex scenarios and once one get past the template matching and understands how and when to use recursion (No you can't reassign a variable in Xslt and you're not supposed to!) I find it to be a dream compared to the mapping tool. I also find the code so much easier to maintain compared to the result from the mapping tool. I mean someone would have to pay me good money to even start figuring out what this map is doing. And the scary thing is that if you worked with BizTalk for a while you probably know that maps like this isn't that rare! I've even seen worse!
Don't get me wrong, Xslt definitely has some major limitations.
Some of the acute limitations of XSLT 1.0 I can think of off the top of my head are: > > * The lack of real string comparison > * No support for dates > * No simple mechanism for grouping > * No querying into RTF's >
And it doesn't take long before one runs up against one of these and suddenly you wish you were back in mapping tool were we just could add scripting functoid and some code or a external assembly. But then you remember ... (Sorry, I know it's painful just to watch it).
There has to be a better way of doing this and combining the best out of the two worlds!
I started looking into to how BizTalk actually solves combining Xslt and the possibility to use external assemblies. After a couple of searches I found Yossi's nice article that explained it to me (from 2005! I'm behind on this one!) and it even turns out that there an example in the BizTalk SDK.
Ok, so now I had what I need. I started a new class library project and began writing some date parsing methods, some padding methods and so on.
It somehow however felt wrong from the start and I got this grinding feeling that I must be reinventing the wheel (I mean these are well know limitations of Xslt and must have been solved before). Even worse I also felt that I was creating a stupid single point of failure as I started using the component from all different maps in my projects and I have actually seen how much pain a bug in similar shared dll:s could cause. Basically a small bug in the component could halt all the process using the library! Finally I realized that this kind of library would be under constant development as we ran into more and more areas of limitations in the our Xslt:s and that would just increase the risk of errors and mistakes.
After some further investigation I found EXSLT which looked like a solution to my problems! A stable, tested library of Xslt extensions that we could take dependency on as it's unlikely to have any bugs and that should include the functionality we're missing in standard Xslt!
How I used EXSLT in BizTalk
These days it's the Xml Mvp crowd over at the Mvp.Xml project who develops and maintains the .NET implementation of EXSLT. So I downloaded the latest binaries (version 2.3). Put the the Mvp.Xml.dll in the GAC. Wrote a short custom extension Xml snippet that looked like this (using what I've learnt from Yossi's article).
<?xml version="1.0" encoding="utf-8"?> <ExtensionObjects> <ExtensionObject Namespace="http://exslt.org/dates-and-times" AssemblyName="Mvp.Xml, Version=220.127.116.11, Culture=neutral, PublicKeyToken=6ead800d778c9b9f" ClassName="Mvp.Xml.Exslt.ExsltDatesAndTimes"/> </ExtensionObjects>
All you define is the Xml namespace you like to use in your Xslt to reference the dll, the full assembly name and finally the name of the class in Mvp.Xml.Exslt you want to use (make sure you also download the source to Xml.Mvp, it helps when looking up in what classes and namespaces different methods are placed).
That means you need one ExtensionObjects block for each class you want you use which really isn't a problem as the methods are nicely structured based on there functionality.
Then we can use this in a Xslt like this:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:S1="http://ExtendedMapping.Schema1" xmlns:S2="http://ExtendedMapping.Schema2" xmlns:exslt="http://exslt.org/dates-and-times" version="1.0"> <xsl:template match="/"> <S2:Root> <Field> <xsl:value-of select="exslt:dateTime()"/> </Field> </S2:Root> </xsl:template> </xsl:stylesheet>
Which gives us the below output. Notice the current time and date! Cool!
<S2:Root xmlns:S1="http://ExtendedMapping.Schema1" xmlns:S2="http://ExtendedMapping.Schema2" xmlns:exslt="http://exslt.org/dates-and-times"> <Field>2008-09-05T20:45:13+02:00</Field> </S2:Root>
All you then have to do in you map is to reference the Xslt and the extension Xml.
Just as final teaser I'll paste a few methods from the EXSLT documentation
Some string methods:
Some date and time methods:
As if this was enough (!) the Mvp Xml project added a couple of there own methods! What about string lowercase and string uppercase - all in Xslt! And about 30 new date-time related methods extra to the standard ones already in EXSLT!
Check out the full documentation here!
Let me know how it works out for you.