How to remove duplicates on BizTalk Functoid Map

Here’s an example where I wanted to create a small XML file with a unique list of TerminalIDs from my application.

On the left, which I had to blur out, the Looping functoid is connected to a parent record that repeats, and the other lines are connect to the source of the TerminalID.

The scripting component has the following “Inline C#” code:

public System.Collections.Generic.List<string> duplicateList = new System.Collections.Generic.List<string>();

public bool IsDuplicate( string terminalID )
     if( duplicateList.Contains( terminalID) )
        return true;
     duplicateList.Add( terminalID );
     return false;

You can see that it creates a collection object called a "Generic.List".  It then adds terminalIDs to that list, after checking if the item is already in the list or not.  It then returns a true or false. 

The logical equals functoid tests the output of the above to "false".  I think it is used to make sure we send a boolean true/false to the item on the right side of the map. Maybe it could be avoided, but I saw this in someone else's map, and I left it for now.  I made one attempt to remove it and reverse the true/false coming out of Scripting Component, but it didn't work. 

In case you didn't know, when set a field on the right side of the map to "false", then that item doesn't get mapped out.  You basically suppress it. 

The output, when I passed two inputs with "ABC" as the terminal ID is as follows: 
<?xml version="1.0"?>
<ns0:UtilListTerminalIDs xmlns:ns0="http://TMW.Integration.Schemas.UtilListTerminalIDs">

Remember that you can right-click the map, and click “Validate” to see the XSLT behind the map. The XSLT file will be shown in the Output window, and you can do a CNTL-Click on the .XSL filename.

Later, I passed two messages to the following C# routine which identifies if a TerminalID was not found in the target database (after doing a query on it). I could have also done the dup logic in the C# routine. This code uses XPath and the XmlDoc.SelectingSingleNode method to lookup the terminal ID in the results of the query. (The database query was previously returned as an XML message in the orchestration.)

I didn’t want the orchestration to continue, because it would get an error later when it tries to insert a row into another table that requires the TerminalID to be in the target database.

        public static string FindMissingTerminalIDsInTRMSTResponse(
                   XmlDocument UtilListTerminalIDs, XmlDocument TRMSResponse)
            string rt = ""; 
            string xpathTerminalIDs = "//TerminalID";
            XmlNodeList terminalNodes = UtilListTerminalIDs.SelectNodes(xpathTerminalIDs);
            int countMatches = 0; 
            int countNodes = 0;
            int countMisMatches = 0; 

            foreach (XmlNode terminalNode in terminalNodes)
                string xpathVerify = "//*[local-name()='TSATRM'][text()='" + terminalNode.InnerText + "']";
                Console.WriteLine("xpathVerify=" + xpathVerify);

                XmlNode testTerminalExistsNode = TRMSResponse.SelectSingleNode(xpathVerify);

                if (testTerminalExistsNode != null)
                    if (countMisMatches > 1)
                        rt = rt + ", ";    // comma separate after the first one 
                    rt = rt + terminalNode.InnerText;


At first, I was going to return a boolean from this method, but then I decided that I would suspend the orchestration if the input had missing TerminalIDs, and the message should list all the missing IDs in a string. That went into my orchestration Suspend Shape.


Leave a Reply