BizTalk Mapper Patterns: How to Map Hierarchical Schema to a Name Value Pair

Posted: October 28, 2012 in BizTalk
Tags: , , ,

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

About these ads
Comments
  1. Steve Russell says:

    Very nice description of the various alternatives, Sandro. Thanks!

  2. Grant says:

    Great article. Just what I was looking for. Any advice on doing the reverse? Thanks

  3. [...] BizTalk Mapper Patterns: How to Map Hierarchical Schema to a Name Value Pair – Nice post that describes the pros and cons of four methods to accomplish a mapping from hierarchical schema to a name value pair. [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s