Say you want to create a map in order to produce the SELECT statement for a WCF-SQL query and you start of with a list of values to include in the where clause.

How to achieve this with the BizTalk Services mapper?

The Source XML:

<ns0:GetProducts xmlns:ns0="http://GetProductsBizTalkService.Schemas">
  <Column>
    <Name>Name_0</Name>
    <Value>Value_0</Value>
  </Column>
  <Column>
    <Name>Name_1</Name>
    <Value>Value_1</Value>
  </Column>
  <Column>
    <Name>Name_2</Name>
    <Value>Value_2</Value>
  </Column>
</ns0:GetProducts>

The Destination XML:

<ns3:Select xmlns:ns3="http://schemas.microsoft.com/Sql/2008/05/TableOp/dbo/Products">
  <ns3:Columns>*</ns3:Columns>
  <ns3:Query>where Name_0='Value_0' and Name_1='Value_1' and Name_2='Value_2'</ns3:Query>
</ns3:Select>

First, how could we do this within XSLT?

This can be done with the following XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:s0="http://GetProductsBizTalkService.Schemas"
                xmlns:ns0="http://schemas.microsoft.com/Sql/2008/05/TableOp/dbo/Products"
                exclude-result-prefixes="msxsl s0">
  <xsl:output method="xml"
              indent="yes"/>

  <xsl:template match="/">
    <xsl:apply-templates select="/s0:GetProducts" />
  </xsl:template>
  <xsl:template match="/s0:GetProducts">
    <ns0:Select>
      <ns0:Columns>*</ns0:Columns>
      <xsl:if test="Column">
        <ns0:Query>
          <xsl:for-each select="Column">
            <xsl:if test='position() = 1'>where </xsl:if>
            <xsl:value-of select="Name"/>='<xsl:value-of select="Value"/>'
            <xsl:if test='position() != last()'> and </xsl:if>
          </xsl:for-each>
        </ns0:Query>
      </xsl:if>
    </ns0:Select>
  </xsl:template>
</xsl:stylesheet>

The result of the above will be:

<?xml version="1.0" encoding="utf-8"?>
<ns0:Select xmlns:ns0="http://schemas.microsoft.com/Sql/2008/05/TableOp/dbo/Products">
  <ns0:Columns>*</ns0:Columns>
  <ns0:Query>
    where Name_0='Value_0'
    and Name_1='Value_1'
    and Name_2='Value_2'
  </ns0:Query>
</ns0:Select>

Finally, how to achieve the same thing with the mapper:

What did we do?

First of all we need a list and the list will contain the list of expressions based on the column name and values:

Name_0='Value_0'
Name_1='Value_1'
Name_2='Value_2'

For this we use the new “Create List” functoid:

include the “ForEach Loop” functoid – in order to loop the “Column” records -:

use a “String Concatenate” in combination with the “Add Item to List” functoid to produce the above list:

Now that we have the list, how to produce the query statement? “Cumulative Concatenate” comes to the rescue:

Since the “Query” element in the destination schema is optional, I also included a “Conditional Assignment” functoid to only map the query in case we have columns on the input.
I also used the “Cumulative Count” functoid to count the number of items in the list and used the “Logical Expression” functoid to check if the value is greater than 0:


Based on that result we will create the “Query” element or not, but first we need to prefix the query with the “where” word using the “String Concatenate” functoid:

Simple!

The thing to remember here is to include a “ForEach” in the “Create List”…

Koen