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 of 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 to this problem, we need to notice that two elements are mapped directly:
- Id to NProcesso.
- and ServiceName to ServiceName.
📝 One-Minute Brief
This post solves the reverse of a common mapping challenge: taking a flattened, repetitive Name-Value Pair structure (often from legacy systems or generic APIs) and recreating a Hierarchical XML structure. It demonstrates the “Value Mapping” pattern, using Equal and Value Mapping functoids to conditionally extract data and place it into specific destination nodes, ensuring a clean and structured output.
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 below:
- We need to repeat the above steps for all the elements, with the exception of the IPRoute element, until we get the following map:
- Because the 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 the 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.
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 on the map and select the option Validate Map.
- In the Output windows, press the CTRL 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 window.
- Right-click and select the View Source option.
We will see that for each element in the destination schema, it will be a one-for-each element:
<xsl:for-each select="Properties/Property>
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Name/text()) , 'Type')" />
<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 , 'Protocol')" />
<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 the Property record, each filled with the elements Name and Value, we will have 50 iterations for each element that we want to map to 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 to 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 the Scripting functoid to the map grid
- In the scripting type, selectthe 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:
This looked like it would be my favorite approach because it is completely 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 works well if all the elements contained in the Properties record are 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 it basically solves all limitations of previous solutions: it’s easy to create (only needs basic knowledge of XSLT and XPath) and doesn’t have performance problems.
To accomplish this, we need to:
- Replace the code of the Scripting functoid, existing in the previous solution, with:
<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>
In this first approach, I tried to keep the code simple, but there is an important limitation in this code … I’m not validating the existence of optional fields. To do that, we need to put the code a little more elaborately:
<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>
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 to the destination schema, it requires that we have to rectify the mapping
Where can I download it?
You can download the complete source code here:
For those looking to move beyond the basics of message transformation, I highly recommend checking out my eBook, BizTalk Mapping Patterns & Best Practices, published in partnership with BizTalk360.
This resource is a deep dive into the real-world challenges of data transformation. It covers:
- Mapping Patterns: From simple field-to-field links to complex structural shifts.
- Performance Optimization: How to build maps that don’t slow down your environment.
- XSLT vs. Functoids: Knowing exactly when to use built-in tools and when to write custom code.
Whether you are maintaining a legacy BizTalk 2010 environment or planning a migration, these patterns are the foundation of clean, maintainable integration.
Download the full eBook here: BizTalk Mapping Patterns & Best Practices
Hope you find this helpful! If you liked the content or found it useful and would like to support me in writing more, consider buying (or helping to buy) a Star Wars Lego set for my son.




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