The out-off box "Index" functiod obviously can not be used to generate such group unique discrete index. Essentially, a BizTalk map will be translated into an internal xlt style sheet after being compiled. The "Index" functoid will reset the starting index to 1 whenever the loop jump from the parent level hierarchy to the child level hierarchy collection.
To resolve this challenge, we need defined a global level variable of the map scope which used to persist and cumulate the index numbers. The Microsoft Functoid allows a global variable been declared in the map scope which makes this technical challenge being easily resolved.
Bellow is the list of C# code to implement the custom IndexCumulateFunctioid. The completed source code can be download here.
using System;
using Microsoft.BizTalk.BaseFunctoids;
using System.Reflection;
using System.Text;
using System.Collections;
using System.Globalization;
namespace IndexGeneratorFunctoid
{
///
/// Summary description for Class1.
///
public class IndexCumulativeFunctoid : BaseFunctoid
{
public IndexCumulativeFunctoid() : base()
{
//ID for this functoid
this.ID = 8001;
// resource assembly must be ProjectName.ResourceName if building with VS.Net
SetupResourceAssembly( "IndexGeneratorResources", Assembly.GetExecutingAssembly() );
//Setup the Name, ToolTip, Help Description, and the Bitmap for this functoid
SetName( "IDS_INDEX_CUMULATIVE_NAME" );
SetTooltip( "IDS_IINDEX_CUMULATIVE_TOOLTIP" );
SetDescription( "IDS_INDEX_CUMULATIVE_DESCRIPTION" );
SetBitmap( "IDB_INDEX_CUMULATIVE_BITMAP" );
SetExternalFunctionName( GetType().Assembly.FullName, "IndexCumulativeFunctoid", "IndexAcumulative" );
AddScriptTypeSupport( ScriptType.CSharp );
//this is a nice way of declaring and maintaining global variables used during Map execution.
SetScriptGlobalBuffer(ScriptType.CSharp, "public int _currentIndex = 0;n" );
this.Category = FunctoidCategory.Cumulative;
this.OutputConnectionType = ConnectionType.AllExceptRecord;
//This functoid can accept variable number of inputs.
this.HasVariableInputs = false;
//Set the minimum and maximum number of parameters to be 1
this.SetMinParams(0);
this.SetMaxParams(0);
}
//this overidden function provides inline code for various number of inputs.
//The inline code builds the contents of the global array variable _globalArray using the parameters
//specified to the function.
protected override string GetInlineScriptBuffer( ScriptType scriptType, int numParams, int functionNumber )
{
if (ScriptType.CSharp == scriptType)
{
StringBuilder builder = new StringBuilder();
builder.Append( "public int IndexAcumulative(object obj)" );
builder.Append( "{n" );
builder.Append( " _currentIndex = _currentIndex + 1;n" );
builder.Append( " return _currentIndex;n" );
builder.Append( "}n" );
return builder.ToString();
}
else
{
return "0";
}
}
}
}