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

Posted: October 28, 2012  |  Categories: BizTalk Maps

In this new mapping pattern, I want to show you how can you transform a 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 to 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 to 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 to this problem we need to notice that two elements 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 map all the elements using the method previously explained.

mapping name value using links

However, this approach has 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

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 do 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 tasks involved, too many links and functoids and most important it can be completely 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 to 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 link 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: you 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 the element and in the second the value of the element:

Table looping functoid configuration

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 do 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

You can download the source code from:
BizTalk Mapper Patterns: Name-Value Transformation Pattern - How to Map Hierarchical Schema to a Name Value PairBizTalk Mapper Patterns: Name-Value Transformation Pattern – How to Map Hierarchical Schema to a Name Value Pair
GitHub

Author: Sandro Pereira

Sandro Pereira lives in Portugal and works as a consultant at DevScope. In the past years, he has been working on implementing Integration scenarios both on-premises and cloud for various clients, each with different scenarios from a technical point of view, size, and criticality, using Microsoft Azure, Microsoft BizTalk Server and different technologies like AS2, EDI, RosettaNet, SAP, TIBCO etc. He is a regular blogger, international speaker, and technical reviewer of several BizTalk books all focused on Integration. He is also the author of the book “BizTalk Mapping Patterns & Best Practices”. He has been awarded MVP since 2011 for his contributions to the integration community.

4 thoughts on “BizTalk Mapper Patterns: How to Map Hierarchical Schema to a Name Value Pair”

Leave a Reply

Your email address will not be published. Required fields are marked *

turbo360

Back to Top