Thursday, 4 April 2013

ForEach Loop in XSLT Biztalk Map



This Article demonstrate, For Each Loop inside custom XSLT 

Create Input and Output Schema.

Input Schema






Output Schema 



  













Output Result:  

For each header and Details records in input, there should be Invoice_det record present in output

Create Custom XSLT for Map.

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var" version="1.0">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
  <xsl:template match="/">
    <xsl:apply-templates select="/input" />
  </xsl:template>
  <xsl:template match="/input">
    <Output>
      <xsl:for-each select="Invoice">
        <xsl:for-each select="Header">
          <Invoice_Det>
            <Batch_Id>
              <xsl:value-of select="BatchId/text()" />
            </Batch_Id>
            <Invoice_No>
              <xsl:value-of select="InvoiceNum/text()" />
            </Invoice_No>
            <Sequence_No>
              <xsl:value-of select="SequenceNum/text()" />
            </Sequence_No>
            <Amount>
              <xsl:value-of select="Amount/text()" />
            </Amount>
          </Invoice_Det>
        </xsl:for-each>
        <xsl:for-each select="Detail">
          <Invoice_Det>
            <Invoice_No>
              <xsl:value-of select="InvoiceNum/text()" />
            </Invoice_No>
            <Sequence_No>
              <xsl:value-of select="SequenceNum/text()" />
            </Sequence_No>
            <Amount>
              <xsl:value-of select="Amount/text()" />
            </Amount>
          </Invoice_Det>
        </xsl:for-each>
      </xsl:for-each>
    </Output>
  </xsl:template>
</xsl:stylesheet>


Test Map with Input :

<input>
<Invoice>
<Header>
<InvoiceNum>1</InvoiceNum>
<SequenceNum>0</SequenceNum>
<BatchId>123</BatchId>
</Header>
<Detail>
<SequenceNum>1</SequenceNum>
<Amount>20</Amount>
<InvoiceNum>1</InvoiceNum>
</Detail>
<Detail>
<SequenceNum>2</SequenceNum>
<Amount>20</Amount>
<InvoiceNum>1</InvoiceNum>
</Detail>
</Invoice>
<Invoice>
<Header>
<InvoiceNum>2</InvoiceNum>
<SequenceNum>0</SequenceNum>
<BatchId>123</BatchId>
</Header>
<Detail>
<SequenceNum>1</SequenceNum>
<Amount>40</Amount>
<InvoiceNum>2</InvoiceNum>
</Detail>
<Detail>
<SequenceNum>2</SequenceNum>
<Amount>40</Amount>
<InvoiceNum>2</InvoiceNum>
</Detail>
</Invoice>
</input>


OutPut Result :
<Output>
<Invoice_Det>
<Batch_Id>123</Batch_Id>
<Invoice_No>1</Invoice_No>
<Sequence_No>0</Sequence_No>
<Amount></Amount>
</Invoice_Det>
<Invoice_Det>
<Batch_Id></Batch_Id>
<Invoice_No>1</Invoice_No>
<Sequence_No>1</Sequence_No>
<Amount>20</Amount>
</Invoice_Det>
<Invoice_Det>
<Batch_Id></Batch_Id>
<Invoice_No>1</Invoice_No>
<Sequence_No>2</Sequence_No>
<Amount>20</Amount>
</Invoice_Det>
<Invoice_Det>
<Batch_Id>123</Batch_Id>
<Invoice_No>2</Invoice_No>
<Sequence_No>0</Sequence_No>
<Amount></Amount>
</Invoice_Det>
<Invoice_Det>
<Batch_Id></Batch_Id>
<Invoice_No>2</Invoice_No>
<Sequence_No>1</Sequence_No>
<Amount>40</Amount>
</Invoice_Det>
<Invoice_Det>
<Batch_Id></Batch_Id>
<Invoice_No>2</Invoice_No>
<Sequence_No>1</Sequence_No>
<Amount>40</Amount>
</Invoice_Det>
</Output>

Tuesday, 2 April 2013

Dynamic Send Port in Pure Messaging



Dynamic send ports do not contain a fixed destination address, only a pipeline. The destination address is determined at run time from a specified property in the message.
We can set Dynamic Send port property inside orchestration inside Expression Shape

MySendPort(Microsoft.XLANGs.BaseTypes.Address) = "http://localhost/testpartner/test.aspx";
MySendPort(Microsoft.XLANGs.BaseTypes.TransportType) = "HTTP";

In case scenario is pure messaging, we can set properties inside receive pipeline.
Set and promote OutboundTransportType and OutboundTransportLocation properties inside receive pipeline

This Article describe how to create custom pipeline component for promote two fields (OutboundTransportType and OutboundTransportLocation)

Step 1: Create Custom Disassembler Component.
  public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            System.Diagnostics.Trace.WriteLine("Pipeline Disassemble Stage Enter");
            msgPart = pInMsg.BodyPart;
            Stream originalStream = pInMsg.BodyPart.GetOriginalDataStream();
            try
            {
                if (msgPart != null)
                {
                    if (originalStream != null)
                    {
                        string stream = string.Empty;
                        // do the disassembling
                        byte[] arrByte = ConvertToByteArray(stream);
                        originalStream = (new MemoryStream(arrByte));
                    }
                }
            }
            catch (Exception)
            {
                System.Diagnostics.Trace.WriteLine("Pipeline Disassemble Stage Exception");
                throw;
            }

            originalStream.Seek(0, SeekOrigin.Begin);
            msgPart.Data = originalStream;
            IBaseMessage outMsg = pInMsg;
            outMsg.BodyPart.Data = originalStream;
            outMsg.Context.Promote("OutboundTransportType",
              "http://schemas.microsoft.com/BizTalk/2003/system-properties",
              "FILE");
            outMsg.Context.Promote("OutboundTransportLocation",
              "http://schemas.microsoft.com/BizTalk/2003/system-properties",
              "D:\\Sample.txt");
            qOutputMsgs.Enqueue(outMsg);
            System.Diagnostics.Trace.WriteLine("Pipeline Disassemble Stage Exit");
        }

        public IBaseMessage GetNext(IPipelineContext pContext)
        {
            if (qOutputMsgs.Count > 0)
            {
                IBaseMessage msg = (IBaseMessage)qOutputMsgs.Dequeue();
                return msg;
            }
            else
                return null;
        }

Step 2: Create Custom Pipeline using custom component.

Step 3: Deploy Pipeline,

Step 4: Create Receive Port with custom pipeline.

Step 5: Create Dynamic Send port with filter BTS.ReceivePortname = “ReceivePortName”