Hi all

Someone at the online general BizTalk forum asked a question about combining two messages
in a map. Now, he all ready knew about creating the map from inside an orchestration,
but let me just quickly summon up for those not knowing this. If you have two messages
inside an orchestration that you need to merge into one message in a map, what you
do is that you drag a transformation shape into your orchestration like this:

DualInputOrchestration

In my example, I have a parallel convoy to get the two input messages into my orchestration.
I then have two different ways of combining the two input messages into one output,
and each is then output.

Anyway, after the transform shape is dragged onto the orchestration designer, you
double-click on it to choose input and output messages like this:

DualInputCreateMap

You can add as many source messages as you want – I have chosen two messages. Make
sure the checkbox at the bottom is selected. Then click “OK” and the mapper will open
up. It will have created an input schema for you, which is basically a root node that
wraps the selected source messages. At runtime, the orchestration engine will take
your messages and wrap them to match this schema and use that as input for the map.

In my case, I have these two schemas:

DualInputSchemaHouseBill 

and

DualInputSchemaWayBill

My output schema looks like this:

DualInputSchemaOutput

The automatically generated map looks like this:

DualInputGeneratedMap

As you can see, the destination schema is just like my output schema, but the input
schema wraps my two input schemas into one schema.

So I have just briefly explained how two create the map that can combine two messages
into one. Now for the functionality inside the map.

Most maps like this can be mapped like any other complex input schema. But sometimes
you need to somehow merge elements inside the source messages into one element/record
in the destination. This automatically becomes different, because the values will
appear in different parts of the input tree.

The requirement that was expressed by the person asking the question in the online
forum was that these two inputs:

DualInputSchemaHouseBillExample

and

DualInputSchemaWayBillExample

and combine them into this:

DualInputSchemaOutputExample

So basically, there is a key that is needed to combine records in the two inputs.
My schemas above are my own schemas that roughly look like the schema that was in
use in the forum.

My first map that will solve the given problem looks like this:

DualInputMapFunctoids

Quite simple, actually. I use the looping functoid to create the right number of output
elements, and I use the iteration and index functoids to get the corresponding values
from the WayBill part of the source schema. The index funtoid can take a lot of inputs.
In my case the path to the element is always the first until the vey last step, where
I need to use the output of the iteration functoid. So I have only two inputs: The
element that loops and the index of the parent of this element because that is the
only place where I need to go to a specific element.

This works very nicely, but it has one serious drawback (and a minor one, which I
will get back to later): It requires that the elements appear in the exact same order
in both inputs. If this restriction can be proven valid, then this is my favorite
solution, since I am a fan of using the built-in functoids over scripting functoids
and custom XSLT if at all possible. I didn’t ask the person who had the issue if this
restriction is valid, but thought I’d try another approach that will work around this
just in case. This requires some XSLT, unfortunately, and the map looks like this:

DualInputMapXSLT

Quite simple, really 🙂 The scripting functoid takes care of the job for me. It is
an “Inline XSLT Call Template” functoid and the script goes like this:

<xsl:template name="BuildOutput">

<xsl:param name="ID" />

<xsl:element name="Output">

<xsl:element name="Number"><xsl:value-of select="$ID"
/></xsl:element>

<xsl:element name="OriginPortId"><xsl:value-of select="/*[local-name()=’Root’
and namespace-uri()=’http://schemas.microsoft.com/BizTalk/2003/aggschema’]/*[local-name()=’InputMessagePart_0′ and
namespace-uri()=”]/*[local-name()=’HousebillRoot’ and namespace-uri()=’http://DualInput.DualSchemaHouseBillInput’]/*[local-name()=’HouseBillsNode’ and
namespace-uri()=”][HouseBillNo = $ID]/*[local-name()=’OriginPortId’ and namespace-uri()=”]"
/></xsl:element>

<xsl:element name="ShippingAddress"><xsl:value-of select="/*[local-name()=’Root’
and namespace-uri()=’http://schemas.microsoft.com/BizTalk/2003/aggschema’]/*[local-name()=’InputMessagePart_1′ and
namespace-uri()=”]/*[local-name()=’WayBillRoot’ and namespace-uri()=’http://DualInput.DualSchemaWayBillInput’]/*[local-name()=’WayBillInfo’ and
namespace-uri()=”][WayBillNo = $ID]/*[local-name()=’ShippingAddress’ and namespace-uri()=”]"
/></xsl:element>

<xsl:element name="ContainerAddress"><xsl:value-of select="/*[local-name()=’Root’
and namespace-uri()=’http://schemas.microsoft.com/BizTalk/2003/aggschema’]/*[local-name()=’InputMessagePart_1′ and
namespace-uri()=”]/*[local-name()=’WayBillRoot’ and namespace-uri()=’http://DualInput.DualSchemaWayBillInput’]/*[local-name()=’WayBillInfo’ and
namespace-uri()=”][WayBillNo = $ID]/*[local-name()=’ContainerAddress’ and namespace-uri()=”]"
/></xsl:element>

</xsl:element>

</xsl:template>

Now this looks complex, but really it isn’t. Let me try to shorten it for you to be
more readable:

<xsl:template name="BuildOutput">

<xsl:param name="ID" />

<xsl:element name="Output">

<xsl:element name="Number"><xsl:value-of select="$ID"
/></xsl:element>

<xsl:element name="OriginPortId"><xsl:value-of select="XXX/*[local-name()=’HouseBillsNode’ and
namespace-uri()=”][HouseBillNo = $ID]/*[local-name()=’OriginPortId’ and namespace-uri()=”]"
/></xsl:element>

<xsl:element name="ShippingAddress"><xsl:value-of select="YYY/*[local-name()=’WayBillInfo’ and
namespace-uri()=”][WayBillNo = $ID]/*[local-name()=’ShippingAddress’ and namespace-uri()=”]"
/></xsl:element>

<xsl:element name="ContainerAddress"><xsl:value-of select="YYY/*[local-name()=’WayBillInfo’ and
namespace-uri()=”][WayBillNo = $ID]/*[local-name()=’ContainerAddress’ and namespace-uri()=”]"
/></xsl:element>

</xsl:element>

</xsl:template>

Here XXX is the XPath from the root node down to the HouseBillsNode node and YYY is
the XPath from the root node down to the WayBillInfo node.

Basically, the script is fired by the map for each HouseBillNo element that appears
(3 in my example) and the script will create an Output element with the HousebillNo
value and i will then use the number to look up the values that correspond to the
key in the other parts of the input.

There are some drawbacks to this solution as well, and I will just try to summon up
the drawbacks here:

Drawbacks for first maps

  1. If the elements do not appear in the exact same order in both inputs, the map will
    fail.

Drawbacks for the second map

  1. The script has not been adjusted to handle optional fields. So it will create the
    output fields no matter if the input fields exist in the source.

Drawbacks for both maps

  1. If the HouseBill input has more elements than the other, then the output will be missing
    values for the elements that would get there values form the second input.
  2. If the HouseBill input has fewer elements than the other, then the output will simply
    not have records corresponding to these extra elements in the WayBill input.
  3. Both scenarios can be handled in the XSLT, naturally, if needed.

There are probably other drawbacks – most of them related to the fact that I was too
lazy to handle all exceptions that might occur. But you should get the idea anyway
🙂

The solution can be found here

.>

Hope this helps some one



eliasen