Posts Tagged ‘Patterns’

Let’s have a look to a little of inside information that will be in my upcoming Book about maps: demystify and clarify some features about the Table Looping Functoid.

First of all this functoid requires at least 3 inputs and a maximum of 100, in which the official documentation states that:

  • Parameter 1: A link from a repeating node in the source schema. The number of instances of this structure that occur in a particular input instance message defines the number of times that the associated table looping grid is processed.
  • Parameter 2: A constant input parameter that defines the number of columns in the associated table looping grid.
  • Parameters 3 – 100: A link from a node in the source schema or from another functoid, such as a Value Extractor functoid, or a constant input parameter. The relative order of parameters 3 – 100 is unimportant.

I think, at least for those who know the minimum about functoid, the last parameter(s), from 3 to 100, does not present any doubts. They are the values that we want to map from the source to the destination. And the order is not important because we need to define the Table Looping Grid property were we will define the order of appearance of these values.

The Table Looping Grid is basically a configurable table containing an arbitrary number of rows, configurable while editing the table, and a number of columns specified by the second input parameter of the Table Looping functoid. Each table cell is configured by using a drop-down list where the entries in the drop-down list are the values from to third through the last input parameters of the Table Looping functoid. These input parameters consist of a combination of the links into the functoid and any constant input parameters that have been defined. If link input parameters have been given a Label property value, that value is shown in the drop-down lists; otherwise, the value of the Link Source property is shown (generally, the former is friendlier than the latter). Constant input parameters are shown according to their constant value.

Important note: However the number of rows present in the Table Looping Grid are not defined in any input parameter from the Table Looping Functoid and in under no circumstances they are dynamic. The number of rows are statically defined during developing in order to apply a specific transformation rule and resolve a particular transformation problem.

Although people use this functoid correctly, especially if we are using it with a repeating record in the source schema, we will see in more detail further on in this chapter, is went we are trying to use this Functoid to transform a flat structure to a recursive structure that we realize that many developers don’t properly understand the first input parameter of this Functoid and to be honest, neither the explanation present in the official documentation will explain it correctly.

Although the Table Looping Functoid states that the first input must be a scoping element linked from a repeating group, that is not really true, in fact for me this description is complete false!

  • A link from a repeating node in the source schema – most common used but not entire true, you can also make use of a constant value, a simple node or an element.
  • The number of instances of this structure that occur in a particular input instance message defines the number of times that the associated table looping grid is processed. – I understand and in a way yes, but sometimes developers understand that this as the number of rows that they have to define in the table Looping Grid, with is not true, or that this input requires a number and in fact this is also not true.

So to be more clear, for me the best description of this parameter is:

  • Parameter 1: the first input parameter defines the action scope of the Table Looping Functoid and it can be defined by a link from a source tree node, repeating record, simple records or even elements, or by a constant value. This means:
    • If the scope is defined by a repeating record or repeating element, the Table Looping functoid will be created/execute in each occurrence of the record or element (in each iteration over the node). We can define this as multiple scope action.
    • If the scope is defined by a simple element or record (only occurs one time), than the Table Looping will be executed only one time. We can define this as simple scope action.
    • If the scope is defined by a simple constant value, regardless if it is an integer, alpha-numeric or string, than the Table Looping will be executed only one time. Again this is a simple scope action.

Table-Looping-Functoid-Scope-defined-by-a-simple-constant-value

Both this options are valid! More details will be found in my upcoming BizTalk Mapping Patterns and Best Practices free eBook.

Basically there are two properties inside the schema element decides whether an element can be absent from the document: Min Occurs and Nillable.

If Min Occurs property is set 0 then that element can be absent from the XML message but if it is set to 1 it has to be present though its value can be empty. This is useful to reduce the size of the document if only not all the elements are mandatory to end systems.

In other hand, if the Nillable property of the element is set to true, this will indicate that the value of an element in the document may be null. This NULL values will be expressed with xsi:nil = true attribute in the element, ex:

<IntExist xsi:nil="true" />

An element with the attribute xsi:nil = true explicitly means that the value is unavailable or unknown at that moment and sometimes the end system explicitly requires to be notified that the value of the element is NULL so that they can take appropriate action.

In this sample scenario we will have a 2 mandatory elements that can be nillable that we need to map to the destination schema. In this scenario all the destination elements are also mandatory and we need to fill them with a valid value or specify the nillable property as true: so if the element exist we need to map the correct source value otherwise we need to set the destination element as nillable.

The first element “DateExist” is a mandatory element that can be null. If null we need to set a null value in the destination element also as null, otherwise we need to map the source value. To accomplish that we need to:

  • Drag one IsNil Functoid from the Toolbox window onto the Grid.
    • Drag a link from the “NillValue” field element in the source schema to the IsNill Functoid
  • Drag one Nil Value Functoid from the Toolbox window onto the Grid.
  • Drag one Logical NOT Functoid from the Toolbox window onto the Grid.
  • Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
  • To create a rule for mapping the value if the element is null
    • Drag a link from the IsNill Functoid to the Nil Value Functoid
    • Drag a link from the Nil Value Functoid to the “NillValueOutput” field element in the destination schema
  • Otherwise, To create a rule for mapping the value if the element different of null
    • Drag a link from the IsNill Functoid to the Logical NOT Functoid
    • Drag a link from the Logical NOT Functoid to the Value Mapping Functoid Functoid
    • Drag a link from the “NillValue” field element in the source schema to the Value Mapping Functoid
    • Drag a link from the Value Mapping Functoid to the “NillValueOutput” field element in the destination schema

Do the exact same logic for the second element present in the source schema.

BizTalk-Mapper-Working-With-Nillable-Values

Sometimes the maps are misunderstood and notorious for producing a lot of unnecessary code that may cause a in some cases lack of performance. So the question that we can and should ask is whether this is the best solution or not to address this type of operations. To respond this question we should also inspect the generated code produce by the BizTalk Mapper:

<xsl:variable name="var:v1" select="string(NillValue/@xsi:nil) = 'true'" />
    <xsl:variable name="var:v2" select="userCSharp:LogicalNot(string($var:v1))" />
    <xsl:variable name="var:v4" select="string(AnotherNilValue/@xsi:nil) = 'true'" />
    <xsl:variable name="var:v5" select="userCSharp:LogicalNot(string($var:v4))" />
    <ns0:OutputSchema>
      <xsl:if test="string($var:v1)='true'">
        <NillValueOutput>
          <xsl:attribute name="xsi:nil">
            <xsl:value-of select="'true'" />
          </xsl:attribute>
        </NillValueOutput>
      </xsl:if>
      <xsl:if test="string($var:v2)='true'">
        <xsl:variable name="var:v3" select="NillValue/text()" />
        <NillValueOutput>
          <xsl:value-of select="$var:v3" />
        </NillValueOutput>
      </xsl:if>
      <xsl:if test="string($var:v4)='true'">
        <AnotherNilValueOutput>
          <xsl:attribute name="xsi:nil">
            <xsl:value-of select="'true'" />
          </xsl:attribute>
        </AnotherNilValueOutput>
      </xsl:if>
      <xsl:if test="string($var:v5)='true'">
        <xsl:variable name="var:v6" select="AnotherNilValue/text()" />
        <AnotherNilValueOutput>
          <xsl:value-of select="$var:v6" />
        </AnotherNilValueOutput>
      </xsl:if>
    </ns0:OutputSchema>
  </xsl:template>

In fact is a pretty decent XSLT code but the reality is that it can be better, we don’t need to use any support variables and we can remove one if condition by replacing the xsl:if condition for one xsl:choose condition.

This is a very simple approach, easy to implement and readable that you should use even in small or large messages (transformations) but only if you have to deal with a small number of nillable element.

However applying this approach in transformation that will need to deal with a large number of nillable elements, can lead to two problems:

  • A lot of unnecessary XSLT code that can in fact and of course always depending in the size of the message can lead to some lack of performance
  • A lot of functoid shapes (4 Functoids) and links (7 links) for each element that can lead to lack of visual Readability

So can we improve this solution for transformations that needs to deal with a large number of nillable elements?

Well that’s the problem, there isn’t a simple solution for that. At the first look you may think that’s easy, just copy the XSLT code inside to a Scripting Functoid and optimize the XSLT code.

However by doing that you will receive an error:

error btm1050: XSL transform error: Unable to write output instance to the following <file:///C:\…\MapNillValuesWithCustomXSLT_output.xml>. Prefix ‘xsi’ is not defined.

The problem is that the nil attribute is defined in the XML Schema instance namespace, http://www.w3.org/2001/XMLSchema-instance (commonly associated with the prefix xsi) and this namespace is not declared by default in the XSL code generated by the BizTalk Mapper.

This namespace is automatically declare only if you use the Nil Functoids in the map.

So the normal solution here is… to bypass the BizTalk Mapper and generate an external XSLT code and add it to the map by specifying the Custom XSLT Path by:

  • Open the map
  • Click the grid zone and on the properties window there will be a “Custom XSLT Path” property.  Click the ellipses and navigate to the file containing the XSLT.

BizTalk-Mapper-Working-With-Nillable-Values-External-XSLT

You then can use a similar code to check and map the elements:

<xsl:choose>
  <xsl:when test="NillValue/@xsi:nil">
    <NillValueOutput>
      <xsl:attribute name="xsi:nil">
        <xsl:value-of select="'true'" />
      </xsl:attribute>
    </NillValueOutput>
  </xsl:when>
  <xsl:otherwise>
    <NillValueOutput>
      <xsl:value-of select="NillValue/text()" />
    </NillValueOutput>
  </xsl:otherwise>
</xsl:choose>

However applying this approach we have a major problem for me:

  • We lose all the BizTalk Mapper functionalities.
Workaround

Well, at least that I know, unfortunately there is no simple way to declared the xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance namespace to the stylesheet of the map.

However we can apply one small workaround, is not perfect but in most of the case it will solve my problems:

  • For only one of the nillable elements we need to use the Nil Functoids explained in the beginning of this post.
    • This will declare automatically the name xsi namespace for us.
  • In the rest of the elements we now can use Scripting Functoids with the optimized XSLT code described above

BizTalk-Mapper-Working-With-Nillable-Values-XSLT

I’m still working to find a better way but until then

You can download the source code from:

BizTalk Mapper: Working With Nillable Values (xsi:nil=”true”) (92.7 KB)
Microsoft | Code Gallery

Exchanging or routing messages between existing applications, systems or external partners is one of the many common scenarios in Enterprise integration solutions. And sometimes they are build base on the same data model, however because they are built in different systems and teams they can have slight small differences like: the order of the elements, the name of the elements, the structure or even the namespace. As a result of that we need to be able to transformed the original message to the expect message by that systems.

BizTalk Mapper provides you with just-in-time assistance, through a shortcut menu, when you create links between two record elements of source and destination schemas:

  • You can create multiple links simultaneously if:
    • Relevant schema structures must be the same (node names are different but order is the same or similar;
    • Or Record, elements or field names must match;
  • You can manually create single links by dragging and dropping the source element to the destination element, if the destination schema don’t have a similar structures or the same names;
  • Or you can use Mass Copy Functoid to copy the element in the input instance message to a destination schema that use the <any> Element (some kind of generic schema). This functoid also copies any and all of its substructure, and re-creates it in the output instance message at the linked node in the destination schema.

The BizTalk Mapper provides you with just-in-time assistance, through a shortcut menu, when you create links between two record elements of source and destination schemas.

So for accomplish that, open your map and:

  • Drag-and-drop the root name of the source schema, in this case “PurchaseOrder” to the root name of the destination schema, which will be in this case “PO”, and release the direct button of the mouse.

just-in-time-assistance-BizTalk-Mapper

  • A windows assistance will pop up were you can select create record-to-record links automatically in the following ways:
    • Direct Link: Using this technique, the BizTalk Mapper links the record from source schema to the selected record in the destination schema. This will not copy any kind of hierarchy structure from the source to the destination, it will only link the record or node.
    • Link by Structure: Using this technique, the BizTalk Mapper attempts to match the Record and Field nodes within the Record nodes being linked according to the structures of those Record nodes, regardless of names of the corresponding nodes within those structures.
    • Link By Name: Using this technique, the BizTalk Mapper attempts to match the Record and Field nodes within the Record nodes being linked according to the names of the corresponding nodes, regardless of their structure, within the Record nodes being linked.
    • Mass Copy: The Mass Copy functoid enables your maps to use schemas that include any and anyAttribute elements. For information about the functoids available in BizTalk Mapper.

Our scenario will have a Purchase Order that will need to be mapped to 3 different systems with 3 different target schemas.

  • The System A have a similar schema of our system, with the same structure and the same names, but they are presented in a different order;
    • Because the destination schema have the same names of the source schema, the best approach in this scenario is to use the Link By Name option
  • The System B have also a similar schema of our system, we as the same order and the same schema structure, however the elements have different names;
    • Because the destination schema have the structure of the source schema, the best approach in this scenario is to use the Link By Structure option
  • The System C have a canonical schema (or generic schema) that will accept any structure.
    • Because the destination schema will accept any kind of structure, the best approach in this scenario is to use the Mass Copy option
Scenario A: How to link the record elements by name

To accomplished that we need:

  • Drag the mouse from the root name “PurchaseOrder” in the source schema, and then drop it to root name “PO” in the destination schema.
  • On the shortcut menu, click “Link by Name” option. The BizTalk Mapper will attempt to match all the Record, Elements and Field nodes under the “PurchaseOrder” node according to their names, regardless of their structure, within the node “PO”.

And the BizTalk Mapper will automatically map all the elements from the source schema to the target schema that have the same name, as the picture bellow will show:

Link-by-Name

Of course this technique as some limitations, the elements need to have the exact same name, and will only work in some scenarios.

Scenario B: How to link the record elements by structure

To accomplished that we need:

  • Drag the mouse from the root name “PurchaseOrder” in the source schema, and then drop it to root name “ExternalPO” in the destination schema.
  • On the shortcut menu, click “Link by Structure” option. The BizTalk Mapper will attempt to match all the Record, Elements and Field nodes under the “PurchaseOrder” node according to the structure of those elements, , regardless of names of the corresponding nodes within those structures, within the node “ExternalPO”.

And the BizTalk Mapper will automatically map all the elements from the source schema to the target schema that have the same structure, as the picture bellow will show:

Link-by-Structure

Again this technique have the same limitations of the previous one.

Scenario C: How to link using a mass copy functoid

To accomplished that we need:

  • Drag-and-drop the Mass Copy functoid from the Toolbox to the map grid page and then:
    • Link the source root name “PurchaseOrder” as input parameter for the Mass Copy functoid;
    • Link the Mass Copy functoid to the destination root name “CanonicalPurchaseOrder” to set the output parameter from the Mass Copy functoid;

Mass-Copy

The only problem in using the Mass Copy functoid is that it will move all the elements and values from the source schema to the destination schema but it also will include the targetNamespace of source schema in the destination schema and this behavior can be a problem in some scenarios.

Example of the map output:

<ns0:CanonicalPurchaseOrder xmlns:ns0="http://BizTalkMapperSemanticTranslatorPattern.CanonicalPurchaseOrder">
 <From xmlns:ns0="http://BizTalkMapperSemanticTranslatorPattern.PurchaseOrder">From_0</From>
 <To xmlns:ns0="http://BizTalkMapperSemanticTranslatorPattern.PurchaseOrder">To_0</To>
 <LineItems xmlns:ns0="http://BizTalkMapperSemanticTranslatorPattern.PurchaseOrder">
 <Item>
 <Product>Product_0</Product>
 <Description>Description_0</Description>
 <Price>10</Price>
 <Quantity>10</Quantity>
 </Item>
 </LineItems>
</ns0:CanonicalPurchaseOrder>

So how can we avoid this behavior?

However sometimes the destination schema expect a different message, without the namespaces in the element:

<CanonicalPurchaseOrder xmlns:ns0="http://BizTalkMapperSemanticTranslatorPattern.CanonicalPurchaseOrder">
  <From>From_0</From>
  <To>To_0</To>
  <LineItems>
     <Items>
        <Product>Product_0</Product>
        <Description>Description_0</Description>
        <Price>10</Price>
        <Quantity>10</Quantity>
     </Items>
  </LineItems>
</CanonicalPurchaseOrder>

I already saw this scenario many times. So how can we accomplish this?

There is no easy way to accomplished this without the need to use custom XSLT and you will need to customize the syntax to your scenario.

In this sample if we need to map everything without namespaces we need to “replace” the Mass Copy functoid for a Scripting functoid:

  • Drag-and-drop the Scripting functoid from the Toolbox to the map grid page and then:
    • And Link the Scripting functoid to the destination root name “CanonicalPurchaseOrder” to set the output parameter from the Scripting functoid;
    • This functoid will not have any input parameters;
  • Double-click in the Scripting functoid to show the Properties window, then:
    • Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script type
    • In the “Inline script” text box enter the following XSLT code without the comments (they are only for explaining the operation of the script):
<CanonicalPurchaseOrder>
      <xsl:for-each select="/s0:PurchaseOrder/*">
        <xsl:if test="local-name()!='LineItems'">
          <xsl:element name="{local-name(.)}">
            <xsl:value-of select="." />
          </xsl:element>
        </xsl:if>
      </xsl:for-each>

      <xsl:choose>
        <xsl:when test="count(/s0:PurchaseOrder/LineItems) &gt; 0">
          <LineItems>
            <xsl:for-each select="/s0:PurchaseOrder/LineItems/*">
              <Items>
                <xsl:for-each select="./*">
                  <xsl:element name="{local-name(.)}">
                    <xsl:value-of select="." />
                  </xsl:element>
                </xsl:for-each>
              </Items>
            </xsl:for-each>
          </LineItems>
        </xsl:when>
      </xsl:choose>
</CanonicalPurchaseOrder>

Basically what we are doing is:

  • The Scripting functoid will not add the root name, so we need to manually add it
  • The we are Getting all the element inside “PurchaseOrder” but because we need to travel all the elements inside the LineItems we need to treat this different, so we will get all the element except the ” LineItems”
  • The next step is check if there is “LineItems”
  • If exist we will travel all the element inside the LineItems (for each)
  • Because the “LineItems” only contain one record we will add this manually but we need an additional cycle this time to travel all the elements inside the record Item

And with that we create our own custom Mass copy Functoid

The sample code is available for download in Code Gallery:.

Automatically Link The Record Elements By Structure, Name or Using Mass Copy (148.5 KB)
Microsoft Code Gallery

Well, I decided to take a few minutes of my vacation to play a little with … BizTalk, renew some knowledge, answer a few emails and maybe try to answer some questions on the forums.

This exercise (or pattern) is actually from a question that I found on the forums: Reg BizTalk Mapping, which I found interesting.

So what’s the best way to map some values from a repeating node into a single node base in some conditions?

Note: you can find all mapping logic of this exercise in the forum, however briefly we have a repeating node “TimeSeries” and based on Path attribute value of “TimeSeries” node we will map on some elements of the output message:

  • If “Path” attribute == “1” then assign the value of “TimedValue” to “Quantity”
  • If “Path” attribute == “2” then assign the value of “TimedValue” to “NRJQuantity”
  • If “Path” attribute == “3” then assign the value of “TimedValue” to “AvgCal”
  • If “Path” attribute == “4” then assign the value of “TimedValue” to “AvgDens”
First Solution: Using only functoids (without custom XSLT)

To solve this mapping problem using this approach, for each element in the destination schema we need to drag:

  • One Equal functoid and drag a link from the attribute “Path” in the source schema to this functoid, this will be the first input parameter in the functoid
    • And in the second parameter we need to put the number that we want to find, in this case: “1”.
  • Drag a Value Mapping functoid to the grid
    • Drag a link from the Equal functoid to this Value Mapping functoid
    • Drag a link from the “TimedValue” element in the source element to the Value Mapping functoid
  • Drag a link from the Equal functoid for the element in question in the destination schema, in this case “Quantity” element
  • And finally we need to drag a link from the Value Mapping functoid to the respective element in the destination schema, in this case again “Quantity” element as you can see in the picture bellow.

map-values-from-repeating-node-into-single-node-using-conditions-with-functoids

  • We need to repeat the above steps for all the element until we get the following map:

map-values-from-repeating-node-into-single-node-using-conditions-with-functoids-all

This solution is correct and in fact is what’s normally we found in this type of mapping problems however this is not the best option in terms of performance. If we analyze the XSLT regenerated by the BizTalk mapping engine by:

  • Right-click in the map and select the option “Validate Map”
  • In the Output windows, press CRTL key and click on the link of “The file in the output XSLT is stored in the following file”, it will open this file in a new windows
  • Right-click and select “View Source” option

We will see that for each element in the destination schema it will be one for-each element:

<ns0:Req>
  <xsl:for-each select="TimeSeries">
    <xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(@Path) , &quot;1&quot;)" />
    <xsl:if test="$var:v1">
      <xsl:variable name="var:v2" select="string(@Path)" />
      <xsl:variable name="var:v3" select="userCSharp:LogicalEq($var:v2 , &quot;1&quot;)" />
      <xsl:if test="string($var:v3)='true'">
        <xsl:variable name="var:v4" select="TimedValues/TimedValue/text()" />
        <ns0:Quantity>
          <xsl:value-of select="$var:v4" />
        </ns0:Quantity>
      </xsl:if>
    </xsl:if>
  </xsl:for-each>

  <xsl:for-each select="TimeSeries">
    <xsl:variable name="var:v5" select="string(@Path)" />
    <xsl:variable name="var:v6" select="userCSharp:LogicalEq($var:v5 , &quot;2&quot;)" />
    <xsl:if test="$var:v6">
      <xsl:if test="string($var:v6)='true'">
        <xsl:variable name="var:v7" select="TimedValues/TimedValue/text()" />
        <ns0:NRJQuantity>
          <xsl:value-of select="$var:v7" />
        </ns0:NRJQuantity>
      </xsl:if>
    </xsl:if>
  </xsl:for-each>
....

This means that if we have 50 occurrences of “TimeSeries” node, we will have 50 iterations for each element that we want to map in the destination schema… so this approach may be easy to implement and somewhat acceptable in small messages is extremely disadvantageous for large message.

Limitations of this approach:

  • Lack of performance
Second Solution: Using Inline XSLT

In this second approach what we will do is take the XSLT code generated by the compiler and optimize it by removing all unnecessary cycles and put this code in a Scripting functoid.

To accomplish this, we need to:

  • Drag Scripting functoid to the map grid
    • In the scripting type select “Inline XSLT” option
    • In the Inline script put the following code:
<xsl:for-each select="TimeSeries">
  <xsl:if test="string(@Path) = '1' ">
    <Quantity>
      <xsl:value-of select="TimedValues/TimedValue/text()" />
    </Quantity>
  </xsl:if>
  <xsl:if test="string(@Path) = '2' ">
    <NRJQuantity>
      <xsl:value-of select="TimedValues/TimedValue/text()" />
    </NRJQuantity>
  </xsl:if>
  <xsl:if test="string(@Path) = '3' ">
    <AvgCal>
      <xsl:value-of select="TimedValues/TimedValue/text()" />
    </AvgCal>
  </xsl:if>
  <xsl:if test="string(@Path) = '4' ">
    <AvgDens>
      <xsl:value-of select="TimedValues/TimedValue/text()" />
    </AvgDens>
  </xsl:if>
</xsl:for-each>
  • Finally drag a link from the Scripting functoid to one element in the destination schema, for example “NRJQuantity”

map-values-from-repeating-node-into-single-node-using-conditions-with-scripting

Limitations of this approach:

  • May have some lack of performance if we work with large message because some unnecessary iterations in the cycle, however it is far more efficient than the first solution.
  • Some warnings saying that some required field has no incoming link.
  • Because we use scripting functoids we cannot read the entire map visually. We need to open the functoids and read, mainly, the XSLT code.
Third Solution: Using Inline XSLT along with XPath queries

After analyzing all the advantages and disadvantages, I decided that I could optimize even more the XSLT script in order to have a better performance but to do this I would have to use a different approach than the one that was used by the BizTalk mapper engine, and for me this is the best approach to accomplish this type of mapping problem, because basically solves all limitations of previous solutions: it’s easy to create (only need basic knowledge of XSLT and XPath) and don’t have performance problems.

To accomplish this, we need to:

  • Replace the code of the Scripting functoid, existing in the previous solution, by:
<xsl:choose>
  <xsl:when test="count(//TimeSeries[@Path='1']) > 0">
    <Quantity>
      <xsl:value-of select="//TimeSeries[@Path='1']/TimedValues/TimedValue/text()" />
    </Quantity>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//TimeSeries[@Path='2']) > 0">
    <NRJQuantity>
      <xsl:value-of select="//TimeSeries[@Path='2']/TimedValues/TimedValue/text()" />
    </NRJQuantity>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//TimeSeries[@Path='3']) > 0">
    <AvgCal>
      <xsl:value-of select="//TimeSeries[@Path='3']/TimedValues/TimedValue/text()" />
    </AvgCal>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//TimeSeries[@Path='4']) > 0">
    <AvgDens>
      <xsl:value-of select="//TimeSeries[@Path='4']/TimedValues/TimedValue/text()" />
    </AvgDens>
  </xsl:when>
</xsl:choose>

map-values-from-repeating-node-into-single-node-using-conditions-with-scripting-2

Limitations of this approach:

  • Because we use scripting functoids we cannot read the entire map visually. We need to open the functoids and read, mainly, the XSLT code.
  • Need basic knowledge of XSLT and XPath
  • Some warnings saying that some required field has no incoming link.
Fourth Solution: Using Inline XSLT along with XPath queries (avoiding warnings)

So to avoid warnings saying that some required field has no incoming link we must split the XSLT code that we use in the last solution (Third Solution) in different blocks for each element in the destination schema

To accomplish this, we need to:

  • Drag four Scripting functoid to the map grid and drag a link from each Scripting functoid to each element in the destination schema
  • For each Scripting functoid:
    • In the scripting type select “Inline XSLT” option
    • In the Inline script put the code that corresponding to the element in the destination element, for example in the first:
<xsl:choose>
  <xsl:when test="count(//TimeSeries[@Path='1']) > 0">
    <Quantity>
      <xsl:value-of select="//TimeSeries[@Path='1']/TimedValues/TimedValue/text()" />
    </Quantity>
  </xsl:when>
</xsl:choose>

map-values-from-repeating-node-into-single-node-using-conditions-with-scripting-3

Limitations of this approach:

  • Because we use scripting functoids we cannot read the entire map visually. We need to open the functoids and read, mainly, the XSLT code.
  • Need basic knowledge of XSLT and XPath

The sample code is available for download in Code Gallery:.

How to map values from a repeating node into a single node using conditions (142.6 KB)
Microsoft Code Gallery

In my last mapping pattern post, I explained how and described the pros and cons of four methods to accomplish a mapping from hierarchical schema to a name value pair… so the logically next step would be to describe the inverse process.

When I decided to implement this mapping I really thought it would be extremely simple and almost not worth talking about… how I was wrong! It became really complicated, and exciting, as I tried to find a solution to optimize and improve the map.

As a developer the first approach we think is to try to solve this mapping problem using only the available functoids, i.e. without custom XSLT. I quickly discarded this option and you will see why.

Note: Before I start the solution for this problem we need to notice that two element are mapped directly:

  • “Id” to “NProcesso”
  • and “ServiceName” to “ServiceName”
First Solution: Using only functoids (without custom XSLT)

To solve this mapping problem using this approach, for each element in the destination schema we need to drag:

  • One Equal functoid and drag a link from the element “Name” in the source schema to this functoid, this will be the first condition in the functoid
    • And in the second condition we need to put the element name of the destination schema that we try to map, for example “Type”.
  • Drag a Value Mapping (Flattening) functoid to the grid
    • Drag a link from the Equal functoid to this Value Mapping (Flattening) functoid
    • Drag a link from the “Value” element in the source element to the Value Mapping (Flattening) functoid
    • And finally we need to drag a link from the Value Mapping (Flattening) functoid to the respective element in the destination schema, in this case “Type” element as you can see in the picture bellow:

Name-value-to-hierarchical-using-only-functoids

  • We need to repeat the above steps for all the element except the “IPRoute” element, until we get the following map:

Name-value-to-hierarchical-using-only-functoids-2

  • Because “IPRoute” element is a repeating element, we need to take a different approach:
    • We need to drag a Looping functoid and drag a link from “Property” record in the source schema to this functoid and then drag a link from the Looping functoid to the “IPRoute” element in the destination schema
    • Then we need to make the exact same steps described earlier (Equal functoid and Value Mapping (Flattening) functoid)
    • But because we want to create the “IPRoute” element ONLY if the name is equal to “IPRoute”, then we need to drag a link from the Equal functoid to the “IPRoute” element in the destination schema.

Name-value-to-hierarchical-using-only-functoids-3

And this is it, it seems simple and it is!! However, this approach suffers from a serious problem that we can only detect by analyzing the XSLT regenerated by the BizTalk mapping engine: Performance!

If we analyze the XSLT regenerated by the BizTalk mapping engine by:

  • Right-click in the map and select the option “Validate Map”
  • In the Output windows, press CRTL key and click on the link of “The file in the output XSLT is stored in the following file”, it will open this file in a new windows
  • Right-click and select “View Source” option

We will see that for each element in the destination schema it will be one for-each element:

<xsl:for-each select="Properties/Property">
  <xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Name/text()) , &quot;Type&quot;)" />
  <xsl:if test="string($var:v1)='true'">
    <xsl:variable name="var:v2" select="Value/text()" />
    <Type>
      <xsl:value-of select="$var:v2" />
    </Type>
  </xsl:if>
</xsl:for-each>
<xsl:for-each select="Properties/Property">
  <xsl:variable name="var:v3" select="string(Name/text())" />
  <xsl:variable name="var:v4" select="userCSharp:LogicalEq($var:v3 , &quot;Protocol&quot;)" />
  <xsl:if test="string($var:v4)='true'">
    <xsl:variable name="var:v5" select="Value/text()" />
    <Protocol>
      <xsl:value-of select="$var:v5" />
    </Protocol>
  </xsl:if>
</xsl:for-each>

This means that if we have 50 occurrences of “Property” record, each filled with the elements Name and Value, we will have 50 iterations for each element that we want to map in the destination schema… in this scenario we have 12 elements, this means 600 iterations and will be worse if we are working with large maps or with high amounts of “Property” record occurrence.

Limitations of this approach:

  • Lack of performance
  • If the destination schema has many elements it takes to much work to do this kind of mapping and because we need many links and functoids to do this simple task it may become difficult to read the map.
  • If we add a new element in the destination schema, it requires that we have to rectify the mapping
Second Solution: Dynamic mapping using Inline XSLT

I soon realized that if I wanted a really good and effective solution, I would have to use custom XSLT.

And the second approach that I thought was trying to make a dynamic mapping, similarly to the third solution that I have accomplished in the “BizTalk Mapper Patterns: How to Map Hierarchical Schema to a Name Value Pair” problem

To accomplish this, we need to:

  • Drag Scripting functoid to the map grid
    • In the scripting type select “Inline XSLT” option
    • In the Inline script put the following code:
<xsl:for-each select="/s0:Provisioning/Properties/Property">
  <xsl:if test="Name/text()!='IPRoute'">
    <xsl:element name="{normalize-space(*[local-name()='Name']/text())}">
      <xsl:value-of select="Value/text()"/>
    </xsl:element>
  </xsl:if>
</xsl:for-each> 

Finally drag a link from the Scripting functoid to the “Type” element in the destination schema:

Name-value-to-hierarchical-Dynamic-mapping-using-Inline-XSLT

This looked like be my favorite approach because is complete dynamic. If another element was added to the destination schema I didn’t need to fix the mapping!

But unfortunately this approach has several serious limitations.

Limitations of this approach:

  • The script only work well if all the elements contained in the “Properties” record, are coming filled in the correct order of the elements in the destination schema.
  • Don’t work with nested records (or sub-records), if you notice in the script I ignore all “IPRoute” names

I could probably find other limitations but for me these two are enough to discard this approach.

Third Solution: Using Inline XSLT along with XPath queries

After analyzing all the advantages and disadvantages, for me this is the best (only) approach to accomplish this type of mapping problem. Again, because basically solves all limitations of previous solutions: it’s easy to create (only need basic knowledge of XSLT and XPath) and don’t have performance problems.

To accomplish this, we need to:

  • Replace the code of the Scripting functoid, existing in the previous solution, by:
<Type>
  <xsl:value-of select="//Properties/Property[Name='Type']/Value/text()" />
</Type>
<Protocol>
  <xsl:value-of select="//Properties/Property[Name='Protocol']/Value/text()" />
</Protocol>
<Pool>
  <xsl:value-of select="//Properties/Property[Name='Pool']/Value/text()" />
</Pool>
<VPNName>
  <xsl:value-of select="//Properties/Property[Name='VPNName']/Value/text()" />
</VPNName>
<IPAddress>
  <xsl:value-of select="//Properties/Property[Name='IPAddress']/Value/text()" />
</IPAddress>
<IPNetmask>
  <xsl:value-of select="//Properties/Property[Name='IPNetmask']/Value/text()" />
</IPNetmask>
<LAN>
  <xsl:for-each select="Properties/Property[Name='IPRoute']">
    <IPRoute>
      <xsl:value-of select="./Value/text()" />
    </IPRoute>
  </xsl:for-each>
</LAN>
<VirtualRouter>
  <xsl:value-of select="//Properties/Property[Name='VirtualRouter']/Value/text()" />
</VirtualRouter>
<IdleTimeout>
  <xsl:value-of select="//Properties/Property[Name='IdleTimeout']/Value/text()" />
</IdleTimeout>
<SessionTimeout>
  <xsl:value-of select="//Properties/Property[Name='SessionTimeout']/Value/text()" />
</SessionTimeout>
<TunnelType>
  <xsl:value-of select="//Properties/Property[Name='TunnelType']/Value/text()" />
</TunnelType>

Name-value-to-hierarchical-Dynamic-mapping-using-Inline-XSLT

In this first approach, I tried to keep the code simple, but there is an important limitation in this code … I’m not validate the existence of optional fields. To do that we need to put the code a little more elaborate:

<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='Type']) > 0">
    <Type>
      <xsl:value-of select="//Properties/Property[Name='Type']/Value/text()" />
    </Type>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='Protocol']) > 0">
    <Protocol>
      <xsl:value-of select="//Properties/Property[Name='Protocol']/Value/text()" />
    </Protocol>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='Pool']) > 0">
    <Pool>
      <xsl:value-of select="//Properties/Property[Name='Pool']/Value/text()" />
    </Pool>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='VPNName']) > 0">
    <VPNName>
      <xsl:value-of select="//Properties/Property[Name='VPNName']/Value/text()" />
    </VPNName>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='IPAddress']) > 0">
    <IPAddress>
      <xsl:value-of select="//Properties/Property[Name='IPAddress']/Value/text()" />
    </IPAddress>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='IPNetmask']) > 0">
    <IPNetmask>
      <xsl:value-of select="//Properties/Property[Name='IPNetmask']/Value/text()" />
    </IPNetmask>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='IPRoute']) > 0">
    <LAN>
      <xsl:for-each select="Properties/Property[Name='IPRoute']">
        <IPRoute>
          <xsl:value-of select="./Value/text()" />
        </IPRoute>
      </xsl:for-each>
    </LAN>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='VirtualRouter']) > 0">
    <VirtualRouter>
      <xsl:value-of select="//Properties/Property[Name='VirtualRouter']/Value/text()" />
    </VirtualRouter>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='IdleTimeout']) > 0">
    <IdleTimeout>
      <xsl:value-of select="//Properties/Property[Name='IdleTimeout']/Value/text()" />
    </IdleTimeout>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='SessionTimeout']) > 0">
    <SessionTimeout>
      <xsl:value-of select="//Properties/Property[Name='SessionTimeout']/Value/text()" />
    </SessionTimeout>
  </xsl:when>
</xsl:choose>
<xsl:choose>
  <xsl:when test="count(//Properties/Property[Name='TunnelType']) > 0">
    <TunnelType>
      <xsl:value-of select="//Properties/Property[Name='TunnelType']/Value/text()" />
    </TunnelType>
  </xsl:when>
</xsl:choose>

Limitations of this approach:

  • Because we use scripting functoids we cannot read the entire map visually. We need to open the functoids and read, mainly, the XSLT code.
  • Need basic knowledge of XSLT and XPath
  • If we add a new element in the destination schema, it requires that we have to rectify the mapping

The sample code is available for download in Code Gallery:.

BizTalk Mapper Patterns: How to Map Name Value Pair to a Hierarchical Schema (59.2 KB)
Microsoft Code Gallery

In this new mapping pattern I want to show you how can you transform an hierarchical schema into a Name/Value Pair record.

The first thing we need to know is how I can read the name of the element from the source schema. By default when we drag a link from the source to the destination schema, the value of the element is mapped in the destination schema, but we can change this behavior in the link properties by choosing “Copy name” in the “Source Links” property:

Copy-name-link-property

So to reach our goal we need to link for the source to the destination schema:

  • The link to the “Name” element set with “Copy name” in the “Source Links” property
  • And the link to the “Value” element set with “Copy text value” (the default value) in the “Source Links” property

first-graft-mapping-name-value

Note: Before I start the solution for this problem we need to notice that two element are mapped directly:

  • “NProcesso” to “Id”
  • and “ServiceName” to “ServiceName”

And one element is not mapped “Tipo_Operacao”. All other elements need to be mapped in the Name/Value Pair record.

First Solution: Using only Links

The first approach we think is to mapped all the element using the method previously explained.

mapping-name-value-using-links-1

However this approach have a problem because don’ the produce a valid message, instead of creating a record for each different element mapped he gathers all the Names and Values ​​in a single record:

<ns0:Provisioning xmlns:ns0="http://SandroPereira.MappingToNameValueRecord.Provisioning">
  <Id>Nprocesso_0</Id>
  <Properties>
  <Property>
  <Name>IPRoute</Name>
  <Name>Type</Name>
  <Name>Protocol</Name>
  <Name>Pool</Name>
  <Name>VPNName</Name>
  <Name>IPAddress</Name>
  <Name>IPNetmask</Name>
  <Name>Profile</Name>
  <Name>VirtualRouter</Name>
  <Name>IdleTimeout</Name>
  <Name>SessionTimeout</Name>
  <Name>TunnelType</Name>
  <Value>IPRoute_0</Value>
  <Value>Type_0</Value>
  <Value>Protocol_0</Value>
  <Value>Pool_0</Value>
  <Value>VPNName_0</Value>
  <Value>IPAddress_0</Value>
  <Value>IPNetmask_0</Value>
  <Value>Profile_0</Value>
  <Value>VirtualRouter_0</Value>
  <Value>IdleTimeout_0</Value>
  <Value>SessionTimeout_0</Value>
  <Value>TunnelType_0</Value>
  </Property>
  <ServiceName>ServiceName_0</ServiceName>
</ns0:Provisioning>

To solve this problem we need to add a Lopping functoid and map all the elements in this functoid:

mapping-name-value-using-links-2

Limitations of this approach:

  • If the source schema has many elements it takes much work to do this kind of mapping and because we need many links to do this simple task it may become difficult to read the map.
  • We’re not validate the existence of optional elements, which causes too many warnings
  • A new element in the source schema requires that we have to rectify the mapping
Second Solution: Using only Links and validate the existence of optional elements

So to avoid warnings of optional elements in the first approach we need to use additional functoids. For each element mapped in the Name/Value Pair we need to drag:

  • One Logical Existence functoid and drag a link from the source element to this functoid
  • And two Value Mapping functoids:
    • Drag a link from the Logical Existence functoid to the first Value Mapping functoid
    • Drag a link from the Logical Existence functoid to the second Value Mapping functoid
    • Drag a link from the source element to the first Value Mapping functoid and in the link properties set with “Copy name” the “Source Links” property
    • Drag a link from the source element to the second Value Mapping functoid and in the link properties set with “Copy text value” the “Source Links” property
    • Drag a link from the first Value Mapping functoid to the element “Name” in the destination schema
    • Drag a link from the second Value Mapping functoid to the element “Value” in the destination schema

mapping-name-value-using-links-handling-opcionals

Limitations of this approach:

  • If the source schema has many elements it takes much work to do this kind of mapping and because we need many links and functoids to do this simple task it may become difficult to read the map.
  • A new element in the source schema requires that we have to rectify the mapping
Third Solution: Using Inline XSLT

This is my favorite approach and why? Because basically solves all limitations of previous solutions: Too many work, too many links and functoids and most important can be complete dynamic, i.e., if another element is added to the source schema I don’t need to fix the mapping!

So how can we accomplish this dynamic mapping?

We need to add to the grid two Scripting functoids:

  • The first scripting functoid is for create a C# function to validate the existence of the element.
    • In the scripting type select “Inline C#” option
    • In the Inline script put the following code:
public string EmptyOrNull(string param)
{
     if(string.IsNullOrEmpty(param))
	return "false";
     return "true";
}
  • The second scripting functoid is for mapping all the element in the Name/Value Pair
    • In the scripting type select “Inline XSLT” option
    • In the Inline script put the following code:
<xsl:element name="Properties">
      <xsl:for-each select="/s0:Request/Body/*">
              <xsl:variable name="var:v2">
                     <xsl:value-of select="."/>
              </xsl:variable>
              <xsl:variable name="var:v1" select="userCSharp:EmptyOrNull(string($var:v2))" />
              <xsl:if test="local-name()!='ServiceName' and local-name()!='LAN' and $var:v1='true'">
                  <xsl:element name="Property">
                     <xsl:element name="Name">
                             <xsl:value-of select="local-name()"/>
                      </xsl:element >
                      <xsl:element name="Value">
                             <xsl:value-of select="."/>
                      </xsl:element >
                </xsl:element>
              </xsl:if>
       </xsl:for-each>
       <xsl:for-each select="/s0:Request/Body/LAN/*">
              <xsl:variable name="var:v2">
                     <xsl:value-of select="."/>
              </xsl:variable>
              <xsl:variable name="var:v1" select="userCSharp:EmptyOrNull(string($var:v2))" />
              <xsl:if test="$var:v1='true'">
                     <xsl:element name="Property">
                     <xsl:element name="Name">
                            <xsl:value-of select="local-name()"/>
                     </xsl:element >
                     <xsl:element name="Value">
                           <xsl:value-of select="."/>
                     </xsl:element >
                     </xsl:element>
              </xsl:if>
       </xsl:for-each>
</xsl:element>

Finally drag a ling from the second scripting functoid to the “Properties# record in the destination schema:

mapping-name-value-using-inline-xslt

Limitations of this approach:

  • Because we use scripting functoids we cannot read the entire map visually. We need to open the functoids and read, mainly, the XSLT code.
Fourth Solution: Using Table Looping functoid

Finally I decided to create a fourth approach using the capabilities of the Table Looping functoid. For me the big difference between this approach and the first two is that is probably to be easier to read.

So instead of using the looping functoid and drag all links from the source directly to the destination schema, we will drag the links all the links from the source schema to the Table Looping functoid… but because you cannot drag to link from the same element to the Table Looping functoid (To map the name and the value) you need to use a workaround:

  • Drag a Table Looping functoid to the map grid
  • For each element drag a String Concatenate functoid to the map grid
    • Drag a link from the source element to the String Concatenate functoid and in the link properties set with “Copy name” the “Source Links” property
    • Drag a link from the String Concatenate functoid to the Table Looping functoid and in the link properties set the “Label” property to the following text “<Element name> Name” (note: your need to change <Element name> to the element concerned, ex: “Type Name”)
    • Drag a link from the source element to the Table Looping functoid and in the link properties set with “Copy text value” the “Source Links” property

In the Table lopping functoid configuration we need to set the first to inputs:

  • The first with the number of element mapped in the Table lopping functoid
  • The second with the number of columns, in this case 2

Table-looping-functoid-configuration

And in the Table Lopping grid we need to manually associate the first column the name of element and in the second the value of the element:

Table-looping-functoid-configuration-2

Finally we need to drag to Table Extractor functoid and configure them to read the first and the second column of the table:

mapping-name-value-using-table-lopping-functoid

Limitations of this approach:

  • If the source schema has many elements it takes much work to do this kind of mapping and because we need many links and functoids to do this simple task it may become difficult to read the map.
  • We’re not validate the existence of optional elements, which causes too many warnings.
  • A new element in the source schema requires that we have to rectify the mapping

The sample code in Code Gallery as this workaround implemented.

BizTalk Mapper Patterns: How to Map Hierarchical Schema to a Name Value Pair (69.3 KB)
Microsoft TechNet Gallery

This topic is not new in my blog, I’ve already talked about this in the past: Calling an external assembly from Custom XSLT – Custom Extension XML (Grid Property) however, I decided to revisit this functionality within BizTalk Server 2010 and you will know why soon.

So is usual in complex maps to have scripting functoid with custom inline XSLT, and sometimes is useful to call custom .Net components directly from XSLT.

Create .Net Component

To illustrate this functionality, I decided to create a Class Library project: MapperExtensionsFunctions with a simple class where it is implemented a method to format the numbers in three decimal places:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace MapperExtensionsFunctions
{
    public class MappingFunctions
    {
        public MappingFunctions()
		{
		}

        public string ToDecimalPoint(string Input)
        {
            CultureInfo ciEN = new CultureInfo("en-US", false);

            double ConvertionDouble = double.Parse(Input, ciEN);
            string Output = string.Format("{0:0.000}", ConvertionDouble);
            return Output;
        }
    }
}
How can we extend BizTalk map to support this functionality?

You can add a custom extension xml file to your solution in order to declare the namespace and use a method from a .Net assembly from XSLT.

The extension file should look something like this:

<ExtensionObjects>
  <ExtensionObject Namespace="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0" AssemblyName="MapperExtensionsFunctions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cdbffba4cc751306" ClassName="MapperExtensionsFunctions.MappingFunctions" />
</ExtensionObjects>

Note: “http://schemas.microsoft.com/BizTalk/2003/ScriptNS0” is the “default namespace”, however you can change it (see more here)

In the properties of your BizTalk Mapper, use the Custom Extension XML property to open the Select Custom Extension XML File dialog box, in which you can select the file that contains the custom extension XML for the map (file above).

Custom-Extension-XML

Finally in your Inline XSLT functoid you can use the methods from the assembly by:

<xsl:variable name="result" xmlns:ScriptNS0="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0" select="ScriptNS0:ToDecimalPoint(MarketPrice/text())" />

Or in this case, inside Inline XSLT Call Template:

<xsl:template name="PriceTemplate">
  <xsl:param name="market" />
  <xsl:param name="owner" />
  <xsl:element name="Price">
    <xsl:variable name="pmarket" xmlns:ScriptNS0="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0" select="ScriptNS0:ToDecimalPoint($market)" />
    <xsl:variable name="powner" xmlns:ScriptNS0="http://schemas.microsoft.com/BizTalk/2003/ScriptNS0" select="ScriptNS0:ToDecimalPoint($owner)" />
    <PriceMarket>
      <xsl:value-of select="$pmarket" />
    </PriceMarket>
    <PriceOwner>
      <xsl:value-of select="$powner" />
    </PriceOwner>
  </xsl:element>
</xsl:template>
Houston we have a problem!

After Build, deploy and configure my project with success I decided to test my solution, but I keep getting the following error:

The Messaging Engine failed while executing the inbound map for the message coming from source URL:”C:\TEMP\PORTS\IN_CAR\*.xml” with the Message Type “http://BizTalk.CallingExternalAssemblyFromInlineXSLT.CarInfo#CarProperty&#8221;. Details:”Cannot find the script or external object that implements prefix ‘ScriptNS0’.”

At first glance, this error suggests that the assembly in question is not published in the GAC… However even after re-publish, the assembly in the GAC the problem remained!

Don’t panic, believe it or not, you did everything right… BizTalk Server 2010/Visual Studio 2010 have a bug (or issue): Visual Studio does not persist the path of Custom Extension XML property in the .BTM file.

So if someone wishes to use an external assembly in via a Inline XSLT/XSLT Template scripting functoid they cannot specify the external assembly through an extension xml file.

I tried to install the latest cumulative update package for BizTalk (CU5) and Visual Studio service pack but the issue still remain active (you can see more detail and vote to fix it here)

Workaround (unfortunately it’smanual)

You need to manually edit .BTM file to add this node between the elements </ScriptTypePrecedence> and <TreeValues>:

<CustomXSLT XsltPath="" ExtObjXmlPath=".\ExternalAssembly.xml" />

Note: Is not mandatory the CustomXSLT node stand between the elements </ScriptTypePrecedence> and <TreeValues> however this is normal behavior of the compiler

However this is a workaround that can cause many problems, especially maintaining this issue… but stay tuned, because in my next post I will explain how we can solve this problem in a better way.

Calling an external assembly from Custom XSLT in BizTalk Server 2010 Maps (65.9 KB)
Microsoft Code Gallery