BizTalk 2004 -> Splitter Pattern Using a Map and Orchestration.

Below is a method to Split one message into multiple messages using a Map inside of a BizTalk Orchestration.

This Splitter pattern is the second demo of a webcast I did on March 28 2005
called: BizTalk Server 2004 Implementing Enterprise Integration Patterns. It can be viewed HERE
as a recorded Webcast. The full BizTalk solution can be downloaded at the end of this blog.

In this particular scenario, an Incoming message contains several production orders.
This message was created from a Normalizer(this is a pattern) Orchestration. A discussion
of the Normalizer Pattern can be found HERE

The abbreviated incoming Normalized XML message looks something like the below:

<Rolls>
  <trk_unit_roll_ageable trk_unit_id="10003" pro_product_id="10031" sch_prod_order_id="10049"/>
  <trk_unit_roll_ageable trk_unit_id="10004" pro_product_id="10024" sch_prod_order_id="10043"/>
  <trk_unit_roll_ageable trk_unit_id="10005" pro_product_id="10022" sch_prod_order_id="10043"/>
  <trk_unit_roll_ageable trk_unit_id="10006" pro_product_id="10022" sch_prod_order_id="10049"/>
  <trk_unit_roll_ageable trk_unit_id="10007" pro_product_id="10022" sch_prod_order_id="10048"/>  
  <trk_unit_roll_ageable trk_unit_id="10008" pro_product_id="10022" sch_prod_order_id="10043"/>  
</Rolls>

From the above message there are three distinct Order Ids:

10049
10043
10048

Therefore the goal is to split the incoming Normalized message into three separate messages,
each with their own unique Order Id and respective line items as below:

Message one:

<Rolls UniqueOrderID=10049>
    <trk_unit_roll_ageable trk_unit_id="10003" pro_product_id="10031" sch_prod_order_id="10049"/>
    <trk_unit_roll_ageable trk_unit_id="10006" pro_product_id="10022" sch_prod_order_id="10049"/>   
</Rolls>

Message two:

<Rolls UniqueOrderID=10043>
    <trk_unit_roll_ageable trk_unit_id="10004" pro_product_id="10024" sch_prod_order_id="10043"/>
    <trk_unit_roll_ageable trk_unit_id="10005" pro_product_id="10022" sch_prod_order_id="10043"/>
    <trk_unit_roll_ageable trk_unit_id="10008" pro_product_id="10022" sch_prod_order_id="10043"/>  
</Rolls>

Message three:

<Rolls UniqueOrderID=10048>
   <trk_unit_roll_ageable trk_unit_id="10007" pro_product_id="10022" sch_prod_order_id="10048"/>  
</Rolls>


One solution to accomplish the above is discussed below :

1) Create an Orchestration to accept the incoming message and split it out into
separate messages:

In the Orchestration:

a) Find the distinct list of Order Ids in the message. One method to do this is to utilize some custom
XSLT in a BizTalk map as below :

<xsl:key name="Code-types" match="trk_unit_roll_ageable" use="@sch_prod_order_id"/>
<xsl:template match="/">
<ns0:Rolls xmlns:ns0="http://ObjectSharp">
<xsl:for-each select="//trk_unit_roll_ageable[count(.| key('Code-types', @sch_prod_order_id)[1]) = 1]">
 <xsl:element name="ProdOrderIds">
  <xsl:attribute name="sch_prod_order_id">
   <xsl:value-of select="@sch_prod_order_id"/>
  </xsl:attribute>
 </xsl:element>
</xsl:for-each>
</ns0:Rolls>
</xsl:template>

This XSLT can be used in a map. A method to include custom XSLT in a map is discussed in more detail HERE

The final constructed message (msgDistinctOrdersIds) contains a list of distinct order ids:

<Rolls>
  <ProdOrderIds sch_prod_order_id="10049"/>
  <ProdOrderIds sch_prod_order_id="10043"/>
  <ProdOrderIds sch_prod_order_id="10048"/>
</Rolls>


b) Use an xpath statement to find a count of Distinct Order Ids.
In this case an xpath statement is used in the orchestration as below:

xpath(msgDistinctOrdersIds,"number(count(/*[local-name()='Rolls' and  namespace-uri()='http://ObjectSharp']/*[local-name()='ProdOrderIds' and namespace-uri()='']))");

In the above example the xpath statement will return a value of three.

c) To create each separate message, a loop shape is used in the orchestration. The number of times to iterate in the loop is the value returned from the
xpath statement of step b).


d) For each iteration in the loop shape:
i) Use an xpath statement to find the current distinct Order Id in the iteration as below:
   varIntSchProdOrderId = xpath(msgDistinctOrdersIds,"number(//ProdOrderIds[" + varStrOrderCounter + "]//@sch_prod_order_id)");
   The message used in the xpath statement is the message created in step a). This is a message with the distinct order ids.
ii)Construct a helper XML message (msgSplitterParameters) that will be used in the map to aid in the splitting.
   In this case this message will contain the unique Order Id of the current iteration. An expression
   shape with the following code is used to create a brand new version of the message in each iteration of the loop.
 
varXMLDomSplittingParametersMsg.LoadXml(@"<ns0:SplitterParameters ProdOrderID=""0"" OrderCount=""0"" UniqueIdentifier=""""  xmlns:ns0=""http://ObjectSharp"" />");

construct msgSplitterParameters
{
   msgSplitterParameters = varXMLDomForSplittingParametersMsg;
   msgSplitterParameters.ProdOrderID = varIntSchProdOrderId;
   msgSplitterParameters.OrderCount = varIntTotalNumberOfDistinctOrders;
   msgSplitterParameters.UniqueIdentifier = varStrUniqueIdentifier;
}

Note: A discussion of how to construct messages in an orchestration is HERE

e) For each iteration of the loop, Use a map in the orchestration and use the original input message to create a (split) 
message with that unique order id:


A map with two inputs (two xml messages) is used to create the final output message. The first source used in the map is the original input message with all order items.
The second source is the parameter message constructed in part d). The whole trick of this implementation is to change this parameter message through each iteration of the loop.
Each iteration will produce the correct split message.

The map is quite simple. The first input is the original input message to create each split message  with one unique order id. The second message (parameter message) is used to help filter out the unique line items with that order id in the first input of the map. A logical Equal functoid in the map is used to do the actual filtering.

For example for the first iteration of the loop in the above example, one of the values in the
parameter message is set to:

msgSplitterParameters.ProdOrderID = "10049"

Then when the map is invoked in the loop, the following split message will be produced :

<Rolls UniqueOrderID=10049>
    <trk_unit_roll_ageable trk_unit_id="10003" pro_product_id="10031" sch_prod_order_id="10049"/>
    <trk_unit_roll_ageable trk_unit_id="10006" pro_product_id="10022" sch_prod_order_id="10049"/>   
</Rolls>

Again the full sample can be downloaded HERE
Read the ReadMe.txt file in the zip file, before unzipping and installing.

Note: That the solution also contains a Normalizer Orchestration and
Aggregator Orchestration that are discussed in other blog entries.

Note: Many methods exist to split messages in BizTalk,
such as using Envelopes, Custom XSLT, XPATH, etc.
Please check out some of the other methods HERE , HERE, HERE, HERE