Posts Tagged ‘Mapper’

While researching for my last post, Thinking outside the box (or not): How to create “Global C# function” to be reused inside a map?, in BizTalk360 blog, I encountered several errors while playing around with maps in order to find an approach that would allow me to create the concept of Global Function. And some of this errors were:

Inline Script Error: must declare a body because it is not marked abstract, extern, or partial

Inline Script Error: ; expected

or

Inline Script Error: Type ‘BizTalkMapper.FunctoidInlineScripts’ already defines a member called ‘FunctionName’ with the same parameter types

CAUSES

The cause for this problem is that you are not correctly declare the body of the Inline C# Function.

Or, if you are trying to reuse an existing Inline C# Function you are doing it properly.

To reuse Inline C# Functions this are the rules that you need to follow:

  • If all of the Scripting Functoids are in the same grid page: In the first Scripting Functoid, linked from the source to the destination, we will have to specify the body function and in the following functoids, we only need the function declaration (no body).
  • If the Scripting Functoids are in different grid pages: The Scripting Functoid that specifies the body function needs to be on the leftmost grid page and the remaining Scripting Functoids (with the function body declared) on the other grid pages to the right. In other words, counting the grid pages from left to right, if the Scripting Functoid that specifies the body function is on the second grid page, the remaining functoids with the function body declared, cannot be placed on the first grid page, they can only be placed from the second grid page (including the second).
SOLUTION

The solution to solve this issue you have two options, you need to follow the rules described above (BizTalk Mapper tips and tricks: How to reuse Scripting Functoids with Inline C# inside the same map) or you need to implement the concept of global C# Function described in my post: Thinking outside the box (or not): How to create “Global C# function” to be reused inside a map?, in resume:

  • Add a Grid page to your map and rename it to “GlobalFunctions”
  • Set this grid as the first grid page of your map (important steap)
  • Drag-and-Drop a Scripting Functoid to the “GlobalFunctions” grid page and place the C# code
  • Do not link any inputs and don’t map (link) this Scripting Functoids to any element in the destination Schema.
  • Double click the earlier Scripting Functoids added to the “GlobalFunctions” grid page and set the expected input values as empty constant values, that by default doesn’t exist
  • Now you can use these functions in other grid pages using only the function declaration

A few weeks ago, while improving an existing solution to fulfil the new business requirements, I encountered the following error while trying to validate or test a BizTalk map:

Exception Caught: The map contains a reference to a schema node that is not valid.  Perhaps the schema has changed.  Try reloading the map in the BizTalk Mapper.  The XSD XPath of the node is: /*[local-name()='<Schema>’]/*[local-name()=’MyRootNode’]/*[local-name()=’MyRecord]/*[local-name()=’MyElement’]

To contextualize the problem, the BizTalk Visual Studio solution I was working on was composed by several projects, but for the propose of this error, let’s say that we had two projects:

  • Schemas Project: containing all the schemas used by the BizTalk Solution;
  • Map Project: containing all the maps used by the BizTalk Solution;

I did the necessary changes on the source schema and they were automatically reflected in the map that I was working on without the need to rebuild the Schema Project. And when I try to test the map, after making all the necessary changes on it, I got the above error.

Which was a little awkward at the point because indeed I changed the contract of the source schema but it was reflect in the map that I was working on. Everything seemed fine, I even try to close and open the map again, but that did not solve the problem

CAUSES

Again, the reason for this error is awkward because the schemas changes were reflected on the map, even if it was a different solution and without rebuilding the Schema Solution. However, the cause for this error is that is referring an invalid or incorrect version of the Schema assembly.

SOLUTION

The solution to solve this issue is simple, you just need to rebuild the entire solution or rebuild the schema project before you try to validate or test the maps.

After the Schema project solution is rebuild the problem will disappear and you will be able to validate or test the map.

Exciting news… Version 1.9.1.0 of BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 R2 and 2013 is now available!

Here’s the change-log for this release:

  • Updated Logical Functoids:
    • The project has sign strong name key solving an issue regarding to “Unable to add BizTalk.Logical.Functoids.dll to the GAC (version 1.9.0.0)” – However, this is a false problem or a BizTalk Deployment Framework that always put functoid assemblies in the GAC, because these functoids are doesn’t need to be place inside the GAC.
  • Updated CRM Functoids:
    • CRM Lookup Functoid: This functoid was updated. This functoid allows you to retrieve a value from CRM lookup field. But now this functoid is also able to performs lookup operation using two different approach: Accessing the CRM database (read-only), for local CRM integration or through the CRM web services if you want avoid giving access to the database or if you have to integrate CRM online.
The new CRM Lookup Functoid

One of the biggest changes in this new version was made by Salvatore Pellitteri that decided to change the previous CRM Lookup Functoid (also created by him) by adding additional features.

This functoid, has the previous one, allows you to retrieve a value from CRM lookup field. However, this new version of the functoid is able to performs lookup operation using two different approach:

  • Accessing the CRM database (read-only), for local CRM integration
  • Through the CRM web services if you want avoid giving access to the database or if you have to integrate CRM online.
Parameters

The functoid takes five mandatory input parameters:

  1. SSO Application Name: the connection parameters are stored inside SSO. Here you have to specify the application name where you decide to store the settings. This allow you to have multiple CRM environments that you can integrate;
  2. CRM Guid Field Name: key field name of which you want to get the value;
  3. CRM Entity Name: CRM entity name on which the resolution will be performed
  4. CRM Input Field Name: imagining having a “code” as input and you want to know the CRM physical key, in this attribute should specify the name of the “code” field.
  5. CRM Input Value: value from source system to resolve

The output of the functoid is a string, Example: 6erg5r-sdrf56-4dfgt5-6ty5r4-456trt 24

new-CRM-Lookup-Functoid-1910

Installation

Create a SSO application.

SQL Server Lookup

Create the following SSO configuration parameters:

  • CrmConnectionType: “sql”
  • CrmDatabaseConnectionString: specify the CRM database connection string

Open SQL Server management console, connect to CRM database and execute the script under CRMLookup.sql file in project folder.

Local CRM web services lookup

Create the following SSO configuration parameters:

CRM Online web services lookup

Create the following SSO configuration parameters:

You can found and download Source Code, Application Binaries and Documentation in CodePlex BizTalk Mapper Extensions UtilityPack home page:

BizTalk Mapper Extensions UtilityPack
CodePlex

 

or from MSDN Code Gallery:

BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 R2 (685.6 KB)
Microsoft | MSDN Code Gallery

Exciting news… Version 1.9.0.0 of BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 R2 and 2013 is now available!

Here’s the change-log for this release:

  • Ten new functoids:
    • Advance Logical AND Functoid
    • Advance Equal Functoid
    • Advance Greater Than Functoid
    • Advance Greater Than or Equal To Functoid
    • Advance Less Than Functoid
    • Advance Less Than or Equal To Functoid
    • Advance Not Equal Functoid
    • Advance Logical NOT Functoid
    • Advance Logical OR Functoid
    • If-Then-Else Functoid
  • Updates on the deployment scripts
What’s new in this version?

Although BizTalk Server provides many functoids to support a range of diverse operations when working with conditional mapping, we are limited to the number of existing operations or otherwise have to use custom XSLT.

This new library – Logical Functoids – includes a suit of functoids to perform a variety of logical operations, often controlling whether a particular element or attribute is created in an output instance message. Most of the Logical Functoids are a replica of the existent Logical Functoids that came out-of-the-box with BizTalk Server with the advantage that these will allow you to connect with others Custom String Functoids. They are fully compatible with existing functoids and don’t produce any more additional code.

biztalk-mapper-extensions-utilitypack-2013-r2-v1-9

See also the reason I decide to create this library here: Why is so hard to make a simple If-Then-Else Functoid? … well, not anymore!

Advance Logical AND Functoid

Use the Advance Logical AND functoid to return the logical AND of input parameters. It determines whether all of the specified input parameters are true.

Parameters

This functoid requires a minimum of two input parameters and a maximum of one hundred:

  • Parameter 1: A value that can be evaluated as either True or False.
  • Parameters 2 – 100: Values that can be evaluated as either True or False.

Returns the logical AND of parameters. True if all of the specified input parameters evaluate to True; False otherwise.

01-Advance-Logical-AND-Functoid

Advance Equal Functoid

Use the Advance Equal functoid to return the value “true” if the first input parameter is equal to the second input parameter. It tests whether the two input parameters are equal.

Parameters

This functoid requires two input parameters:

  • Parameter 1: A value to be tested for equality with the parameter 2.
  • Parameter 2: A value to be tested for equality with the parameter 1.

Returns “True” if the values of the two input parameters are equal; “False” otherwise.

02-Advance-Equal-Functoid

Advance Greater Than Functoid

Use the Advance Greater Than functoid to return the value “true” if the first input parameter is greater than the second input parameter. It tests whether the first input parameter is greater than the second input parameter.

Parameters

This functoid requires two input parameters:

  • Parameter 1: A value to be tested to determine whether it is greater than parameter 2.
  • Parameter 2: A value to be tested to determine whether it is greater than parameter 1.

Returns “True” if the value of the first input parameter is greater than the value of the second input parameter; “False” otherwise.

03-Advance-Greater-Than-Functoid

Advance Greater Than or Equal To Functoid

Use the Advance Greater Than or Equal To functoid to return the value “true” if the first input parameter is greater than or equal to the second input parameter. It tests whether the first input parameter is greater than or equal to the second input parameter.

Parameters

This functoid requires two input parameters:

  • Parameter 1: A value to be tested to determine whether it is greater than or equal to parameter 2.
  • Parameter 2: A value to be tested to determine whether it is greater than or equal to parameter 1.

Returns “True” if the value of the first input parameter is greater than or equal to the value of the second input parameter; “False” otherwise.

04-Advance-Greater-Than-or-Equal-To-Functoid

Advance Less Than Functoid

Use the Advance Less Than functoid to return the value “true” if the first input parameter is less than the second input parameter. It tests whether the first input parameter is less than the second input parameter.

Parameters

This functoid requires two input parameters:

  • Parameter 1: A value to be tested to determine whether it is less than parameter 2.
  • Parameter 2: A value to be tested to determine whether it is less than parameter 1.

Returns “True” if the value of the first input parameter is less than the value of the second input parameter; “False” otherwise.

05-Advance-Less-Than-Functoid

Advance Less Than or Equal To Functoid

Use the Advance Less Than or Equal To functoid to return the value “true” if the first input parameter is less than or equal to the second input parameter. It tests whether the first input parameter is less than or equal to the second input parameter.

Parameters

This functoid requires two input parameters:

  • Parameter 1: A value to be tested to determine whether it is less than or equal to parameter 2.
  • Parameter 2: A value to be tested to determine whether it is less than or equal to parameter 1.

Returns “True” if the value of the first input parameter is less than or equal to the value of the second input parameter; “False” otherwise.

06-Advance-Less-Than-or-Equal-To-Functoid

Advance Not Equal Functoid

Use the Advance Not Equal functoid to return the value “true” if the first input parameter is not equal to the second input parameter. It tests whether the two input parameters are not equal.

Parameters

This functoid requires two input parameters:

  • Parameter 1: A value to be tested for inequality with parameter 2.
  • Parameter 2: A value to be tested for inequality with parameter 1.

Returns “True” if the values of the two input parameters are not equal; “False” otherwise.

07-Advance-Not-Equal-Functoid

Advance Logical NOT Functoid

Use the Advance Logical NOT functoid to return the logical inversion of the input parameter. Use to logically negate the value of the Boolean input parameter.

Parameters

This functoid requires one input parameter only:

  • Parameter 1: A value that can be evaluated as either True or False.

Returns “True” if the specified input parameter evaluates to False; “False” otherwise.

08-Advance-Logical-NOT-Functoid

Advance Logical OR Functoid

Use the Advance Logical OR functoid to return the logical OR of input parameters. The input parameters have to be Boolean or numeric. It determines whether any of the specified input parameters are true.

Parameters

This functoid requires a minimum of two input parameters and a maximum of one hundred:

  • Parameter 1: A value that can be evaluated as either True or False.
  • Parameters 2 – 100: Values that can be evaluated as either True or False.

Returns “True” if any of the specified input parameters evaluate to True; “False” otherwise.

09-Advance-Logical-OR-Functoid

If-Then-Else Functoid

Use the If-Then-Else Functoid to return a value from one of two input parameters based on a condition. If the condition (first input) is True, then the value of the second input parameter is returned, otherwise the Third input is returned.

Parameters

This functoid requires three input parameters:

  • Boolean representing the result of a previous condition
  • The value to be returned if the condition is True.
  • The value to be returned if the condition is False.

If the condition is True, then the value of the second input parameter is returned, otherwise the Third input is returned.

10-If-Then-Else-Functoid

You can found and download Source Code, Application Binaries and Documentation in CodePlex BizTalk Mapper Extensions UtilityPack home page:

BizTalk Mapper Extensions UtilityPack
CodePlex

 

or from MSDN Code Gallery:

BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 R2 (685.6 KB)
Microsoft | MSDN Code Gallery

Sometimes I ask myself: Why is so hard to make a simple If-Then-Else Functoid, or even so painful to do an If-Then-Else operation, using BizTalk mapper?

I don’t mean to say that it is complicated, quite the opposite, is quite easy to make If…Then…Else statements using the Mapper. You can use If…Then…Else statements, to be completely correct, you can use something related to an If…Then…Else statements, to execute blocks of statements depending on the Boolean value of a condition by, normally, using:

  • One Logical Functoid (Logical Existence, Logical String, Logical Numeric, Equal, Greater Than, Less Than and so on) to determine:
    • whether the Record, Field Element, or Field Attribute node that is linked to it exists or have a valid value in a particular input instance message
    • or if a condition match.
  • One Logical NOT Functoid to negate the Logical Functoid
  • And two Value Mapping Functoids to returns the value that we want to linked based on the result of the condition

BizTalk-out-of-the-box-if-then-else-condition

In this sample, if the “Operation” element is equal to “Create”

  • Then: you will map the value of the element “ValueA” from the source schema to the element “Result” in the destination schema
  • Else (otherwise): you will map the value of the element “ValueB” from the source schema to the element “Result” in the destination schema

So, this functoid chain will provide a secondary path of execution when an “if” clause evaluates to false, the Else path. I said earlier: “something related to an If…Then…Else statement” because, programming speaking, If…Then…Else  statements are implemented by:

//C#
if(condition)
{
    //something if true
}
else
{
    //something if false
}

Or

<!-- XSLT -->
<xsl:choose>
  <xsl:when test="expression">
    ... something if true ...
  </xsl:when>
  <xsl:otherwise>
    ... something if false ...
  </xsl:otherwise>
</xsl:choose>

But in fact what this functoid chain does is two If statements

<!-- something if true -->
<xsl:if test="string($var:v1)='true'">
  <xsl:variable name="var:v2" select="ValueA/text()" />
  <Result>
    <xsl:value-of select="$var:v2" />
  </Result>
</xsl:if>
<!-- something if false (var:v3 contains the negation of var:v1) -->
<xsl:if test="string($var:v3)='true'">
  <xsl:variable name="var:v4" select="ValueB/text()" />
  <Result>
    <xsl:value-of select="$var:v4" />
  </Result>
</xsl:if>

This approach is good for small messages, but even with small messages, the Mapper will add many unnecessary code and operations. Because of that I decided to create a If-Then-Else Functoid to use in these situations and improve a little more the performance of the map, of course, undoubtedly, that the best option and with most performance to make conditions is using custom XSLT code (but this is another story).

The annoying things in using this out-of-the-box functois are:

  • We get these  annoying warnings (but they are useful in many scenarios) when we validate the maps:
    • warning btm1004: The destination node “Result” has multiple inputs. For a destination node to have multiple inputs, one of its ancestors should be connected to a looping functoid.
  • And for a simple if-then-else operation we need to use a minimum of 4 functoids. If we have several conditions inside the map, it will be easily filled with functoids and in result, will become a little confused and sometimes difficult to manager.
  • And, obvious, we will have several unnecessary operations.
So, why is so hard to make an If-Then-Else Functoid?

What I want to archive is create a custom functoid that accepts 3 inputs:

  • A Boolean – the result of a previous Logical Functoid (Logical Existence, Logical String, Logical Numeric, Equal, Greater Than, Less Than and so on)
  • And two inputs

Were the custom Functoid will return a value from one of two input parameters based on a condition.

  • If the condition (first input) is True, then the value of the second input parameter is returned;
  • Otherwise the Third input is returned.

Translating to C# code, will be something like this:

public string IfThenElseOperation(string condition, string trueValue, string falseValue)
{
    if (System.Convert.ToBoolean(condition))
        return trueValue;
    return falseValue;
}

Note: I will not address this topic here, this is content deserved a completely different post and dedicated to the topic, but the best option that you have is create a custom functoid belonging to the String functoid category (if you like it, put a comment in the post and I will address this topic in another time/post).

However, if you do that, you will find that, out-of-the-box, it is impossible to create a custom functoid based on a Logical Functoid and the reason why this is true is that, all Logical Functoids available out-of-the-box with BizTalk only accept the following outputs connection types:

  • ConnectionType.Element
  • ConnectionType.FunctoidAssert
  • ConnectionType.FunctoidNilValue
  • ConnectionType.FunctoidKeyMatch
  • ConnectionType.FunctoidTableLooping
  • ConnectionType.FunctoidValueMapping
  • ConnectionType.FunctoidScripter
  • ConnectionType.FunctoidLogical;

ConnectionType Enumeration: Specifies the types of connections that can be used as inputs or outputs for a functoid. This enumeration has a FlagsAttribute attribute that allows a bitwise combination of its member values.

ConnectionType.FunctoidString is not allowed in all the existing Logical Functoids. And that is the reason why you will find impossible to create a custom functoid based on a Logical functoid (don’t know the reason why Microsoft decide to implement this limitation)

How did I solve (or I overcame) this limitation?

To solve (work around) this limitation, so that I could create and use a custom if-then-else functoid, at the same time be fully compatible with existing functoids and don’t produce any more additional code, I was force to create my own personal custom Logical Functoids:

  • Advance Logical AND Functoid
  • Advance Equal Functoid
  • Advance Greater Than Functoid
  • Advance Greater Than or Equal To Functoid
  • Advance Less Than Functoid
  • Advance Less Than or Equal To Functoid
  • Advance Not Equal Functoid
  • Advance Logical NOT Functoid
  • Advance Logical OR Functoid

Toolbox-with-custom-logical-functoids

That have the same behavior as the out-of-the-box Logical Functoids:

  • Logical AND Functoid
  • Equal Functoid
  • Greater Than Functoid
  • Greater Than or Equal To Functoid
  • Less Than Functoid
  • Less Than or Equal To Functoid
  • Not Equal Functoid
  • Logical NOT Functoid
  • Logical OR Functoid

with the advantage that also accept the String output connection type.

base.OutputConnectionType = ConnectionType.FunctoidString | ConnectionType.Element | ConnectionType.FunctoidAssert | ConnectionType.FunctoidNilValue | ConnectionType.FunctoidKeyMatch | ConnectionType.FunctoidTableLooping | ConnectionType.FunctoidValueMapping | ConnectionType.FunctoidScripter | ConnectionType.FunctoidLogical;

By doing that, I can create my if-then-else custom functoid:

namespace BizTalk.CustomAdvanced.Functoids
{
    [Serializable]
    public class IfThenElse : BaseFunctoid
    {
        public IfThenElse()
            : base()
        {
            //ID for this functoid
            this.ID = 10900;

            // resource assembly must be ProjectName.ResourceName if building with VS.Net
            SetupResourceAssembly("BizTalk.Logical.Functoids.LogicalResources", Assembly.GetExecutingAssembly());

            //Setup the Name, ToolTip, Help Description, and the Bitmap for this functoid
            SetName("IDS_IFELSEFUNCTOID_NAME");
            SetTooltip("IDS_IFELSEFUNCTOID_TOOLTIP");
            SetDescription("IDS_IFELSEFUNCTOID_DESCRIPTION");
            SetBitmap("IDS_IFELSEFUNCTOID_BITMAP");

            //category for this functoid. This functoid goes under the String Functoid Tab in the
            this.Category = FunctoidCategory.String;

            // Set the limits for the number of input parameters. This example: 1 parameter
            this.SetMinParams(3);
            this.SetMaxParams(3);

            // Add one line of code as set out below for each input param. For multiple input params, each line would be identical.
            this.AddInputConnectionType(ConnectionType.AllExceptRecord); //first input
            this.AddInputConnectionType(ConnectionType.AllExceptRecord); //Second input
            this.AddInputConnectionType(ConnectionType.AllExceptRecord); //Third input

            // The functoid output can go to any node type.
            this.OutputConnectionType = ConnectionType.AllExceptRecord;

            SetScriptBuffer(ScriptType.CSharp, this.GetCSharpBuffer());
            HasSideEffects = false;
        }

        private string GetCSharpBuffer()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("public string IfThenElseOperation(string condition, string trueValue, string falseValue)\n");
            builder.Append("{\n");
            builder.Append("\tif (System.Convert.ToBoolean(condition))\n");
            builder.Append("\t\treturn trueValue;\n");
            builder.Append("\treturn falseValue;\n");
            builder.Append("}\n");
            return builder.ToString();
        }
    }
}

And have the ability to connect my logical functoids to a custom String functoid. Of course you need to use it wisely!

BizTalk-custom-if-then-else-condition

The beauty of this approach is that:

  • We reduce the functoids chain. By using less functoids we simplify the map visually, and this is very useful when you have a lot of conditions, even if they are simple conditions.
  • We will improve the map performance a little more, compared to the use of out-of-the-box functoids
    • Using Custom If-Then-Else Functoid:
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Operation/text()) , &quot;Create&quot;)" />
<xsl:variable name="var:v2" select="userCSharp:IfThenElseOperation(string($var:v1) , string(ValueA/text()) , string(ValueB/text()))" />

    <ns0:Output>
      <Result>
        <xsl:value-of select="$var:v2" />
      </Result>
    </ns0:Output>

public bool LogicalEq(string val1, string val2)
{
	bool ret = false;
	double d1 = 0;
	double d2 = 0;
	if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2))
	{
		ret = d1 == d2;
	}
	else
	{
		ret = String.Compare(val1, val2, StringComparison.Ordinal) == 0;
	}
	return ret;
}

public string IfThenElseOperation(string condition, string trueValue, string falseValue)
{
	if (System.Convert.ToBoolean(condition))
		return trueValue;
	return falseValue;
}

public bool IsNumeric(string val)
{
	if (val == null)
	{
		return false;
	}
	double d = 0;
	return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}

public bool IsNumeric(string val, ref double d)
{
	if (val == null)
	{
		return false;
	}
	return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}
    • Using Out-of-the-box Functoids:
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Operation/text()) , &quot;Create&quot;)" />
<xsl:variable name="var:v3" select="userCSharp:LogicalNot(string($var:v1))" />

    <ns0:Output>
      <xsl:if test="string($var:v1)='true'">
        <xsl:variable name="var:v2" select="ValueA/text()" />
        <Result>
          <xsl:value-of select="$var:v2" />
        </Result>
      </xsl:if>
      <xsl:if test="string($var:v3)='true'">
        <xsl:variable name="var:v4" select="ValueB/text()" />
        <Result>
          <xsl:value-of select="$var:v4" />
        </Result>
      </xsl:if>
    </ns0:Output>
  
public bool LogicalEq(string val1, string val2)
{
	bool ret = false;
	double d1 = 0;
	double d2 = 0;
	if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2))
	{
		ret = d1 == d2;
	}
	else
	{
		ret = String.Compare(val1, val2, StringComparison.Ordinal) == 0;
	}
	return ret;
}

public bool LogicalNot(string val)
{
	return !ValToBool(val);
}

public bool IsNumeric(string val)
{
	if (val == null)
	{
		return false;
	}
	double d = 0;
	return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}

public bool IsNumeric(string val, ref double d)
{
	if (val == null)
	{
		return false;
	}
	return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}

public bool ValToBool(string val)
{
	if (val != null)
	{
		if (string.Compare(val, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return true;
		}
		if (string.Compare(val, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return false;
		}
		val = val.Trim();
		if (string.Compare(val, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return true;
		}
		if (string.Compare(val, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return false;
		}
		double d = 0;
		if (IsNumeric(val, ref d))
		{
			return (d > 0);
		}
	}
	return false;
}
  • You don’t need to deploy any of these custom functoids (advance logical functoids or/and if-the-else functoid) to your production environment, you only need to have then in your development environment to be used inside Visual Studio because all of them are custom inline functoids, i.e., they will add the necessary code inside the XSLT file:
  • And finally, you can use all the custom advance Logical Functoids allow side with the out-of-the-box Logical Functoids without any impact and without producing additional code, because they will produce the exact same code of out-of-the-box Logical Functoids!

BizTalk-custom-and-out-of-the-box-if-then-else-condition-side-by-side

Generated code:

<!-- Custom Functoid -->
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Operation/text()) , &quot;Create&quot;)" />
<xsl:variable name="var:v2" select="userCSharp:IfThenElseOperation(string($var:v1) , string(ValueA/text()) , string(ValueB/text()))" />

<!-- out-of-the-box Functoids -->
<xsl:variable name="var:v3" select="string(Operation/text())" />
<xsl:variable name="var:v4" select="userCSharp:LogicalEq($var:v3 , &quot;Create&quot;)" />
<xsl:variable name="var:v6" select="userCSharp:LogicalNot(string($var:v4))" />

    <ns0:Output>
<!-- Custom Functoid -->
      <Result>
        <xsl:value-of select="$var:v2" />
      </Result>
<!-- out-of-the-box Functoids -->
      <xsl:if test="string($var:v4)='true'">
        <xsl:variable name="var:v5" select="ValueA/text()" />
        <Total>
          <xsl:value-of select="$var:v5" />
        </Total>
      </xsl:if>
      <xsl:if test="string($var:v6)='true'">
        <xsl:variable name="var:v7" select="ValueB/text()" />
        <Total>
          <xsl:value-of select="$var:v7" />
        </Total>
      </xsl:if>
    </ns0:Output>
  </xsl:template>

<!-- Both out-of-the-box Functoids and custom functoids will produce this LogicalEq code! -->
public bool LogicalEq(string val1, string val2)
{
	bool ret = false;
	double d1 = 0;
	double d2 = 0;
	if (IsNumeric(val1, ref d1) && IsNumeric(val2, ref d2))
	{
		ret = d1 == d2;
	}
	else
	{
		ret = String.Compare(val1, val2, StringComparison.Ordinal) == 0;
	}
	return ret;
}

public string IfThenElseOperation(string condition, string trueValue, string falseValue)
{
	if (System.Convert.ToBoolean(condition))
		return trueValue;
	return falseValue;
}

public bool LogicalNot(string val)
{
	return !ValToBool(val);
}

public bool IsNumeric(string val)
{
	if (val == null)
	{
		return false;
	}
	double d = 0;
	return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}

public bool IsNumeric(string val, ref double d)
{
	if (val == null)
	{
		return false;
	}
	return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}

public bool ValToBool(string val)
{
	if (val != null)
	{
		if (string.Compare(val, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return true;
		}
		if (string.Compare(val, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return false;
		}
		val = val.Trim();
		if (string.Compare(val, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return true;
		}
		if (string.Compare(val, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0)
		{
			return false;
		}
		double d = 0;
		if (IsNumeric(val, ref d))
		{
			return (d > 0);
		}
	}
	return false;
}

May not be the perfect solution, I agree on that but I found a very interesting and useful approach for many scenarios. I hope you enjoy it, because I have been used it a lot lately 🙂

BizTalk-custom-and-out-of-the-box-if-then-else-condition-side-by-side-2

The functoids will be available in the next version of BizTalk Mapper Extensions UtilityPack, until then you have all the source code and samples here:

BizTalk Mapper: How to create a custom If-Then-Else Functoid (18,6 KB)
Microsoft | Code Gallery

As most of you already know, last month I presented a session at BizTalk Summit 2015 London event about “BizTalk Server tips and tricks for developers and admins” (You can check the video recording of my session here)

It was a lightweight session (30 minutes) about useful tips that we can use in our daily work, because it was a small session I didn’t had enough time to cover everything, so I end up creating a “Director’s cut…” session with additional tips that you can check in the presentation slides here.

Today, and because I already received some emails regarding this topic, I will address the “Database Lookup functoid

We can use the Database Lookup functoid to extract information from a database and store it as a Microsoft® ActiveX® Data Objects (ADO) recordset. This functoid requires four input parameters in the following order:

  • Parameter 1: A value for which to search in the specified database, table, and column.
  • Parameter 2: The full connection string for the database with a provider, machine name, database and authentication (an ActiveX Data Objects .NET (ADO.NET) connection string)
  • Parameter 3: The name of the table in the database in which to search.
  • Parameter 4: The name of the column in the table in which to search.

The functoid is actually quite simple to use, however, the main problem that developers face when they use it refers to the second parameter: the connection string. And why?

First: What is the correct value for the connection string?

I always find hard to remember the correct value for the connection string to be used inside this functoid.

Database-Lookup-Functoid-sample-configuration

The Easiest way to make sure we are using the correct connection string value and for not having to remember this by head is to create a simple Universal Data Link (.udl) File… set OLE DB provider connection parameters and test the connection to check if everything is correct.

To accomplish this we need to:

  • · Navigate to a folder in your system, can be in the desktop or preferably in a folder under your BizTalk visual studio solution, let’s call it “Resources”.
  • Create a text file and name it “ODBCConnectionTest.udl”
    • The name of the file is not important, the important part is the extension, it must be “.udl”
  • Double click the file you just created.

create-Universal-Data-Link-udl-File

  • On the Provider Tab, select the appropriate OLE DB provider for the type of data you want to access and then Next
    • In my case it is “Microsoft OLE DB Provider for SQL Server”

Universal-Data-Link-udl-Properties-Provider-tab

  • In the Connection tab, specify:
    • Where your data is located, typically the server and database name.
    • How to connect to it using an OLE DB provider: Use Windows NT integrated security or Use a specific user name and password
    • In this particular case, you need to provide the SQL Server, the database name we want to connect.

Universal-Data-Link-udl-Properties-Connection-tab

  • Then you can and should click on “Test Connection…” button to attempt a connection to the specified data source. If no connection is made, review the settings. Otherwise click “Ok”

Universal-Data-Link-udl-Properties-Test-Connnection

After data Open the “ODBCConnectionTest.udl” file in notepad and you will find the connection string value that you can copy and use it in the second parameter of the Database Lookup Functoid.

Open-Universal-Data-Link-udl-File-notepad

This will lead us to the second problem that you can face using this functoid: using the connection string statically inside the Database Lookup Functoid

Hard-coding the SQL connection strings might lead to maintenance overhead and serviceability issues.

Important considerations:

  • You shouldn’t Hard-coding this value directly in the functoid otherwise it will be a nightmare when you deploy this to a different environment.
  • You can and you should store this parameter in a different storage location (SSO, Registry or others) and get this value using a scripting Functoid or custom functoid which can then be linked to the Database Lookup Functoid, like the:
    • BTSNTSvc Config Get Functoid: This functoid allows you to get configuration parameters from BTSNTsvc.exe.config. If there is no section specified, the functoid reads from the AppSettings.
    • Windows Registry Config Get Functoid: This functoid allows you to get configuration parameters from Windows Registry.
    • SSO Config Get Functoid: This functoid allows you to get configuration parameters from SSO Database.
    • Rule Engine Config Get Functoid: This functoid allows you to obtain a definition value from a Vocabulary in the Business Rules Engine.

In my personal opinion I advice you to use SSO or BRE to store this configuration parameters. All of these custom functoids are available in the BizTalk Mapper Extensions UtilityPack.

TIP-10-Database-Lookup-functoid

You can found and download the Source Code on MSDN Code Gallery:

BizTalk Mapper: How to use Database Lookup Functoid
Microsoft | MSDN Code Gallery

Exciting news… Version 1.8.0.0 of BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 is now available!

But before talking about the change-log of this version there is another subject that I want to talk first… This project as two new members that was responsible for all the new functionalities available in this version:

  • Martijn Schiedon, Integration architect at ValueBlue (http://www.valueblue.nl) and a Dutch BizTalk community member.
  • And Salvatore Pellitteri. He is Developer Team Manager in Microsys Srl. He works on integration application projects using BizTalk Server and on business intelligence projects using SQL Server platform. He works with BizTalk Server since the first version and has worked in many big integration project with several Italian enterprise organizations using many technologies like SAP, Oracle, SQL Server, AS400, J.D. Edwards and HL7. Salvatore has his own blog https://pellitterisbiztalkblog.wordpress.com/ on which he shares his experiences.

Here’s the change-log for this release:

  • Seven new functoids:
    • MSCRM Map Helper Base Types Functoid
    • MSCRM Map Helper Guid Functoid
    • MSCRM Map Helper Money Functoid
    • MSCRM Map Helper Option Value Functoid
    • MSCRM Map Helper References Functoid
    • XPath Functoid
    • Add SharePoint 2013 Document Set Functoid

What’s new in this version?

Although BizTalk Server provides many functoids to support a range of diverse operations when working with conditional mapping, we are limited to the number of existing operations or otherwise have to use custom XSLT.

MSCRM Map Helper Base Types Functoid

Use this functoid when you want map CRM base data types such as “xs:string”, “xs:int” and so on.

Parameters

The functoid takes three mandatory input parameters:

  • Source Field: Link from source schema field value.
  • Target Field Name: CRM target field name.
  • Target Field Type: CRM target field type (Example: “xs:dateTime”).

The output of this functoid should be linked to:

  • “/<Schema>/<CRM_Operation>/entity/Attributes/KeyValuePairOfstringanyType/key”.
MSCRM Map Helper Guid Functoid

Use this functoid when you want map CRM guid type.

Parameters

The functoid takes two mandatory input parameters:

  • Source Field: Link from source schema field value.
  • Target Field Name: CRM target field name

The output of this functoid should be linked to:

  • “/<Schema>/<CRM_Operation>/entity/Attributes/KeyValuePairOfstringanyType/key”.

You may use this functoid in combination with CRM Lookup functoid, where first find for entity guid and then use the result to map to the destination schema.

MSCRM Map Helper Money Functoid

Use this functoid when you want map CRM money type.

Parameters

The functoid takes two mandatory input parameters:

  • Source Field: Link from source schema field value.
  • Target Field Name: CRM target field name.

The output of this functoid should be linked to:

  • “/<Schema>/<CRM_Operation>/entity/Attributes/KeyValuePairOfstringanyType/key”.
MSCRM Map Helper Option Value Functoid

Use this functoid when you want map CRM option value type.

Parameters

The functoid takes two mandatory input parameters:

  • Source Field: Link from source schema field value.
  • Target Field Name: CRM target field name.

The output of this functoid should be linked to:

  • “/<Schema>/<CRM_Operation>/entity/Attributes/KeyValuePairOfstringanyType/key”.
MSCRM Map Helper References Functoid

Use this functoid when you want map CRM reference type.

Parameters

The functoid takes three mandatory input parameters:

  • Source Field: Link from source schema field value.
  • Target Field Name: CRM target field name.
  • Entity Name: CRM referenced entity.

The output of this functoid should be linked to:

  • “/<Schema>/<CRM_Operation>/entity/Attributes/KeyValuePairOfstringanyType/key”.
MSCRM Map Helper Functoids

These functoids allow you to Integrate Directly with the Dynamics CRM SOAP API, avoiding the use of inline XSLT Call template script functoid.

MSCRM requires that different data types are specified in a different way. For this reason, we provide a set of functoid each for specific data type..

Use this functoids in two steps:

First Step

MSCRM-Map-Helper-Functoids-1

Second Step

MSCRM-Map-Helper-Functoids-2

XPath Functoid

This functoid natively integrates custom XPath queries in the BizTalk mapper. This unique functoid which is a powerful competitor to the ScripterFunctoid or a custom XSLT stylesheet and mixes exceptionally well with other functoids.

Parameters

The functoid takes one mandatory input parameter and one optional parameter:

  • The first parameter specifies an absolute or relative XPath expression, which becomes a native part of the generated XSLT.
  • The (optional) second parameter is a link to the source tree node that becomes the (looping) context for the XPath expression.

This defines the current context node for the XPath expression and allows the use of relative XPath expressions. Additionally, the mapper will generate a looping construct for that linked node where appropriate.

The functoid output can be linked to a destination schema node or serve as input to other functoids.

XPath-Custom-Functoids

See more information at The case of the forgotten Functoid – By Martijn Schiedon

Add SharePoint 2013 Document Set Functoid

Creates a Document Set in an existing SharePoint 2013 List. It is a requirement that the SharePoint list contains a custom content-type of type document set.

Parameters

The following parameters are required:

  • string siteUrl = SharePoint Site Url
  • string listName = SharePoint List Name containing the custom content-type Document Set
  • string docSetContentTypeName = Document Set Content Type name
  • string newDocSetName=Name of the to document set to created

Comment: An custom content-type of type documentset needs to be available in SharePoint.

You can found and download Source Code, Application Binaries and Documentation in CodePlex BizTalk Mapper Extensions UtilityPack home page:

BizTalk Mapper Extensions UtilityPack
CodePlex

 

or from MSDN Code Gallery:

BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 (628.8 KB)
Microsoft | MSDN Code Gallery

Exciting news… Version 1.7.0.1 of BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 is now available!

Project Description

BizTalk Mapper Extensions UtilityPack is a set of libraries with several useful Functoids to include and use it in a map, which will provide an extension of BizTalk Mapper capabilities.

Here’s the change-log for this release:

  • Fixes bugs in the String Replace Functoid
What’s new in this minor version?

This is a minor release of this project that is intended to fix some one minor problem reported in the String Replace Functoid.

It was reported that when trying to be replace a Carriage Return\Line Feed (“\r\n”) inside an element the functoid didn’t work and the reason way this happen is that the XSLT code will translate the string “\r\n” to “\\r\\n”. This release will fix that problem. It may not work for every “special characters” however if you find some more problems you can report them that we will address them.

You can found and download Source Code, Application Binaries and Documentation in CodePlex BizTalk Mapper Extensions UtilityPack home page:

BizTalk Mapper Extensions UtilityPack
CodePlex

 

or from MSDN Code Gallery:

BizTalk Mapper Extensions UtilityPack for BizTalk Server 2013 (628.8 KB)
Microsoft | MSDN Code Gallery

Let’s have a look to a little of inside information that will be in my upcoming Book about maps: demystify and clarify some features about the Table Looping Functoid.

First of all this functoid requires at least 3 inputs and a maximum of 100, in which the official documentation states that:

  • Parameter 1: A link from a repeating node in the source schema. The number of instances of this structure that occur in a particular input instance message defines the number of times that the associated table looping grid is processed.
  • Parameter 2: A constant input parameter that defines the number of columns in the associated table looping grid.
  • Parameters 3 – 100: A link from a node in the source schema or from another functoid, such as a Value Extractor functoid, or a constant input parameter. The relative order of parameters 3 – 100 is unimportant.

I think, at least for those who know the minimum about functoid, the last parameter(s), from 3 to 100, does not present any doubts. They are the values that we want to map from the source to the destination. And the order is not important because we need to define the Table Looping Grid property were we will define the order of appearance of these values.

The Table Looping Grid is basically a configurable table containing an arbitrary number of rows, configurable while editing the table, and a number of columns specified by the second input parameter of the Table Looping functoid. Each table cell is configured by using a drop-down list where the entries in the drop-down list are the values from to third through the last input parameters of the Table Looping functoid. These input parameters consist of a combination of the links into the functoid and any constant input parameters that have been defined. If link input parameters have been given a Label property value, that value is shown in the drop-down lists; otherwise, the value of the Link Source property is shown (generally, the former is friendlier than the latter). Constant input parameters are shown according to their constant value.

Important note: However the number of rows present in the Table Looping Grid are not defined in any input parameter from the Table Looping Functoid and in under no circumstances they are dynamic. The number of rows are statically defined during developing in order to apply a specific transformation rule and resolve a particular transformation problem.

Although people use this functoid correctly, especially if we are using it with a repeating record in the source schema, we will see in more detail further on in this chapter, is went we are trying to use this Functoid to transform a flat structure to a recursive structure that we realize that many developers don’t properly understand the first input parameter of this Functoid and to be honest, neither the explanation present in the official documentation will explain it correctly.

Although the Table Looping Functoid states that the first input must be a scoping element linked from a repeating group, that is not really true, in fact for me this description is complete false!

  • A link from a repeating node in the source schema – most common used but not entire true, you can also make use of a constant value, a simple node or an element.
  • The number of instances of this structure that occur in a particular input instance message defines the number of times that the associated table looping grid is processed. – I understand and in a way yes, but sometimes developers understand that this as the number of rows that they have to define in the table Looping Grid, with is not true, or that this input requires a number and in fact this is also not true.

So to be more clear, for me the best description of this parameter is:

  • Parameter 1: the first input parameter defines the action scope of the Table Looping Functoid and it can be defined by a link from a source tree node, repeating record, simple records or even elements, or by a constant value. This means:
    • If the scope is defined by a repeating record or repeating element, the Table Looping functoid will be created/execute in each occurrence of the record or element (in each iteration over the node). We can define this as multiple scope action.
    • If the scope is defined by a simple element or record (only occurs one time), than the Table Looping will be executed only one time. We can define this as simple scope action.
    • If the scope is defined by a simple constant value, regardless if it is an integer, alpha-numeric or string, than the Table Looping will be executed only one time. Again this is a simple scope action.

Table-Looping-Functoid-Scope-defined-by-a-simple-constant-value

Both this options are valid! More details will be found in my upcoming BizTalk Mapping Patterns and Best Practices free eBook.

Basically there are two properties inside the schema element decides whether an element can be absent from the document: Min Occurs and Nillable.

If Min Occurs property is set 0 then that element can be absent from the XML message but if it is set to 1 it has to be present though its value can be empty. This is useful to reduce the size of the document if only not all the elements are mandatory to end systems.

In other hand, if the Nillable property of the element is set to true, this will indicate that the value of an element in the document may be null. This NULL values will be expressed with xsi:nil = true attribute in the element, ex:

<IntExist xsi:nil="true" />

An element with the attribute xsi:nil = true explicitly means that the value is unavailable or unknown at that moment and sometimes the end system explicitly requires to be notified that the value of the element is NULL so that they can take appropriate action.

In this sample scenario we will have a 2 mandatory elements that can be nillable that we need to map to the destination schema. In this scenario all the destination elements are also mandatory and we need to fill them with a valid value or specify the nillable property as true: so if the element exist we need to map the correct source value otherwise we need to set the destination element as nillable.

The first element “DateExist” is a mandatory element that can be null. If null we need to set a null value in the destination element also as null, otherwise we need to map the source value. To accomplish that we need to:

  • Drag one IsNil Functoid from the Toolbox window onto the Grid.
    • Drag a link from the “NillValue” field element in the source schema to the IsNill Functoid
  • Drag one Nil Value Functoid from the Toolbox window onto the Grid.
  • Drag one Logical NOT Functoid from the Toolbox window onto the Grid.
  • Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
  • To create a rule for mapping the value if the element is null
    • Drag a link from the IsNill Functoid to the Nil Value Functoid
    • Drag a link from the Nil Value Functoid to the “NillValueOutput” field element in the destination schema
  • Otherwise, To create a rule for mapping the value if the element different of null
    • Drag a link from the IsNill Functoid to the Logical NOT Functoid
    • Drag a link from the Logical NOT Functoid to the Value Mapping Functoid Functoid
    • Drag a link from the “NillValue” field element in the source schema to the Value Mapping Functoid
    • Drag a link from the Value Mapping Functoid to the “NillValueOutput” field element in the destination schema

Do the exact same logic for the second element present in the source schema.

BizTalk-Mapper-Working-With-Nillable-Values

Sometimes the maps are misunderstood and notorious for producing a lot of unnecessary code that may cause a in some cases lack of performance. So the question that we can and should ask is whether this is the best solution or not to address this type of operations. To respond this question we should also inspect the generated code produce by the BizTalk Mapper:

<xsl:variable name="var:v1" select="string(NillValue/@xsi:nil) = 'true'" />
    <xsl:variable name="var:v2" select="userCSharp:LogicalNot(string($var:v1))" />
    <xsl:variable name="var:v4" select="string(AnotherNilValue/@xsi:nil) = 'true'" />
    <xsl:variable name="var:v5" select="userCSharp:LogicalNot(string($var:v4))" />
    <ns0:OutputSchema>
      <xsl:if test="string($var:v1)='true'">
        <NillValueOutput>
          <xsl:attribute name="xsi:nil">
            <xsl:value-of select="'true'" />
          </xsl:attribute>
        </NillValueOutput>
      </xsl:if>
      <xsl:if test="string($var:v2)='true'">
        <xsl:variable name="var:v3" select="NillValue/text()" />
        <NillValueOutput>
          <xsl:value-of select="$var:v3" />
        </NillValueOutput>
      </xsl:if>
      <xsl:if test="string($var:v4)='true'">
        <AnotherNilValueOutput>
          <xsl:attribute name="xsi:nil">
            <xsl:value-of select="'true'" />
          </xsl:attribute>
        </AnotherNilValueOutput>
      </xsl:if>
      <xsl:if test="string($var:v5)='true'">
        <xsl:variable name="var:v6" select="AnotherNilValue/text()" />
        <AnotherNilValueOutput>
          <xsl:value-of select="$var:v6" />
        </AnotherNilValueOutput>
      </xsl:if>
    </ns0:OutputSchema>
  </xsl:template>

In fact is a pretty decent XSLT code but the reality is that it can be better, we don’t need to use any support variables and we can remove one if condition by replacing the xsl:if condition for one xsl:choose condition.

This is a very simple approach, easy to implement and readable that you should use even in small or large messages (transformations) but only if you have to deal with a small number of nillable element.

However applying this approach in transformation that will need to deal with a large number of nillable elements, can lead to two problems:

  • A lot of unnecessary XSLT code that can in fact and of course always depending in the size of the message can lead to some lack of performance
  • A lot of functoid shapes (4 Functoids) and links (7 links) for each element that can lead to lack of visual Readability

So can we improve this solution for transformations that needs to deal with a large number of nillable elements?

Well that’s the problem, there isn’t a simple solution for that. At the first look you may think that’s easy, just copy the XSLT code inside to a Scripting Functoid and optimize the XSLT code.

However by doing that you will receive an error:

error btm1050: XSL transform error: Unable to write output instance to the following <file:///C:\…\MapNillValuesWithCustomXSLT_output.xml>. Prefix ‘xsi’ is not defined.

The problem is that the nil attribute is defined in the XML Schema instance namespace, http://www.w3.org/2001/XMLSchema-instance (commonly associated with the prefix xsi) and this namespace is not declared by default in the XSL code generated by the BizTalk Mapper.

This namespace is automatically declare only if you use the Nil Functoids in the map.

So the normal solution here is… to bypass the BizTalk Mapper and generate an external XSLT code and add it to the map by specifying the Custom XSLT Path by:

  • Open the map
  • Click the grid zone and on the properties window there will be a “Custom XSLT Path” property.  Click the ellipses and navigate to the file containing the XSLT.

BizTalk-Mapper-Working-With-Nillable-Values-External-XSLT

You then can use a similar code to check and map the elements:

<xsl:choose>
  <xsl:when test="NillValue/@xsi:nil">
    <NillValueOutput>
      <xsl:attribute name="xsi:nil">
        <xsl:value-of select="'true'" />
      </xsl:attribute>
    </NillValueOutput>
  </xsl:when>
  <xsl:otherwise>
    <NillValueOutput>
      <xsl:value-of select="NillValue/text()" />
    </NillValueOutput>
  </xsl:otherwise>
</xsl:choose>

However applying this approach we have a major problem for me:

  • We lose all the BizTalk Mapper functionalities.
Workaround

Well, at least that I know, unfortunately there is no simple way to declared the xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance namespace to the stylesheet of the map.

However we can apply one small workaround, is not perfect but in most of the case it will solve my problems:

  • For only one of the nillable elements we need to use the Nil Functoids explained in the beginning of this post.
    • This will declare automatically the name xsi namespace for us.
  • In the rest of the elements we now can use Scripting Functoids with the optimized XSLT code described above

BizTalk-Mapper-Working-With-Nillable-Values-XSLT

I’m still working to find a better way but until then

You can download the source code from:

BizTalk Mapper: Working With Nillable Values (xsi:nil=”true”) (92.7 KB)
Microsoft | Code Gallery