Mapping Fundamentals - XSLT Call Templates
I'm creating a new series of posts related to using the BizTalk Mapper. I know, it's certainly less sexy than Pipeline Testing Framework (seriously, follow that link) or many other BizTalk subjects, but so much of the magic of BizTalk happens in the mapping.
In my experience, when people are introduced to the BizTalk Mapper they get it very quickly. The user interface is straight forward for most of what you need to do in mapping output. But certainly not all. Take for example some data that looks like this :
<?xml version="1.0" encoding="utf-8" ?>
<MyRoot>
<ref qualifier="D2" value="999999999" />
<ref qualifier="XX" value="999999999" />
<ref qualifier="ZZ" value="XX-YYYYYYYY" />
<nm qualifier="NI" value="999999999" />
</MyRoot>
Your mission, should you choose to accept it is simple. Output one and only one value to destination schema in a node called Identifier which contains either the value of the 'value' attribute of the 'nm' element if the matching qualifier is 'ZZ' or if that does not exist the 'value' attribute of any 'ref' element containing a 'qualifier' attribute of 'ZZ'. If neither exists, then output the constant value 'N/A'.
The catch? Both nodes can both exist with the proper qualifier, and 'nm' must take precedence in that case.
Now, I've no doubt at all that someone could come up with some combination of functoids which might solve this problem. But we must remember that in the end a map is just XSLT and this problem is supremely easy in XSLT and extremely difficult with the mapper. The solution, as you've likely already guessed, is an XSLT Call Template Scripting Functoid.
An XSLT Call Template Scripting Functoid lets you inject your own XSLT into the middle of a map. No need to take the effort of writing the full XSLT yourself if only one or two mappings are giving you trouble. Obviously to be able to write such a functoid you need to understand XSLT, which if you are mapping is a good skill to have anyway. In this simple example we don't even have to deal with parameters. By entering a template as follows, you can solve this problem in a few short lines.
<xsl:template name="MapIdentifier">
<xsl:variable name="nmValue" select="/MyRoot/nm[@qualifier='ZZ']/@value" />
<xsl:variable name="refValue" select="/MyRoot/ref[@qualifier='ZZ']/@value" />
<xsl:element name="Identifier">
<xsl:choose>
<xsl:when test="$nmValue">
<xsl:value-of select="$nmValue"/>
</xsl:when>
<xsl:when test="$refValue">
<xsl:value-of select="$refValue"/>
</xsl:when>
<xsl:otherwise>N/A</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
Some things to remember when working with XSLT Call Templates.
- Only use these when needed. I recently heard Roy Osherove give the same advice regarding Regular Expression and he was right. Both RegEx and XSLT Call Templates are more cryptic and harder for someone coming after you to decipher. Use them when you must, when they save you time, but don't lean on them for everything.
- The Template name must be unique within the map. If you copy-paste the template and don't change the name then only one version will be run. If you later modify one of them and start going nuts trying to figure out why the second isn't behaving properly, check your names.
- XSLT Call Templates must create the destination node. Element or Attribute they don't care, when you write one of these you are taking on the job of outputting that node, namespace and all.
I hope this has been a good quick primer on using XSLT Call Templates. If you've got a topic you'd like covered, leave a comment!
[Post Script : Before anyone comments, the example XML given was deliberately rendered similar to an EDI structure because this is a common problem in EDI mappings.]