Sunday, November 25, 2012

Modifying vocabulary without increasing the version in BRE

There are times when a developer/analyst wants to modify the vocabulary of the BRE without changing the version of the current vocabulary. This can be done with the help of the BizTalkRuleEngineDb which is created when we install our BizTalk Server. 




















I have created a vocabulary called AgeValidation as shown below :











When we create a vocabulary and publish it then a database entry occurs into the Vocabulary table of BizTalkRuleEngineDb database as shown below :














There are several fields in this table but there are 3 fields that are of our interest i.e. nStatus, nMajor, nMinor. When we creating the vocabulary and when it is saved the nStatus field value in DB changes to 0, and when we publish the vocabulary its status changes to 1.

How do we modify the published vocabulary ?

Simply update the nStatus of your vocabulary to 0 and now refresh your BRE. Now our vocabulary will be in saved status and we can easily modify the vocabulary and publish it later on.


All about nMajor and nMinor :

The nMajor and nMinor fields are nothing but indication of the version of your vocabulary.
I have now created 3 versions of same vocabulary :










Now the effect on the vocabulary table in SQL is like this :







This means that when we create a new version of the vocabulary nMinor of the vocabulary keep on increasing.

Tuesday, November 13, 2012

Splitting a Flat-file with multiple records to multiple files with single record.



In BizTalk we can split a flat-file with multiple records to multiple files with single record.
This can be done with Envelope schema or using the below method.

Scenario : 

Suppose we have a input flat-file with multiple records of Purchase Orders of various customers.
Output should be a different file with single Purchase order of the customer.

Solution :

Input File structure:

191,201,44,Sam
192,202,45,John
193,203,46,Jeorge
194,204,47,Kelly
195,205,48,Kristin
196,206,49,Kim


Note : There is an enter at the end of the file.

Source Schema :

Create a source schema with a parent record Root and its child record PurchaseOrder.
Set child delimiter for Root node to 0x0D 0x0A i.e. enter and child order to Postfix.













In the above pic highlighted is the properties that we need to set i.e Group Max occur =1 and Group Min occur =0.

PurchaseOrder record properties :

Set child delimiter for PurchaseOrder node to ',' i.e. comma and child order to Infix.













In the above pic highlighted is the properties that we need to set i.e Max occur =1 and Min occur =0.


Destination Schema :














Map :














Receive Pipeline :














Output Files :














There were 6 records in the input files, hence in there are 6 XML files in the output.

Port Creation\Configuration :

Receive Port & Receive Location- Create a receive port and a receive location after deploying the solution. Select receive pipeline created in the solution on receive location and poll for a specific location using *.txt mask.

Send Port - Create a send port with filter property set to receive port name and in outbound map select the map created in the solution.

How this works :

Setting the Max occur property =1 is responsible for debatching the flat file. When we set Max occur prperty = unbounded, it automatically receive multiple records of the file. In the same manner if we set Max occur =1 schema will only take a single record at a time, mapping will be done for this record and a separate file will be created for this record. Actually all this work is done by the receive pipeline. It will debatch the file while seeing the Max occur property =1 set on the schema.


Using Logical Existence functoid to remove empty node generation in BizTalk Mapper.


Generation of empty node in our XML is a common problem. We can halt the generation of empty nodes in BizTalk Mapper by the use of Logical Existence functiod.

Scenario :
                   Suppose we have to map the Customer's details. We have two records i.e. Customer (which contains header details) and Customer_Details (which contains details) in source schema. In destination schema we have three records i.e. Customer_Header, Customer_Details and ShippingAddress.

Now suppose that the source schema record Customer_Details is not mandatory so can be present or not, and it is mapped to Customer_Details and Address records of Destination Schema.
Now when the source schema record Customer_Details is not present then it creates the empty records.

Source Schema :














Destination Schema :












Input XML file without Customer_Details record :

<ns0:Customer_Data xmlns:ns0="http://Using_LogicalExistense.Customer_SourceSchema">
  <Customer>
    <CustomerID>21</CustomerID>
    <Customer_FName>Micheal</Customer_FName>
    <Customer_LName>Cole</Customer_LName>
  </Customer>
</ns0:Customer_Data>



Map without Logical existence :












Output after Test Map using above XML file :













In the above result Cusomer_Details and ShippingAddress are generating empty.Mapping the Logical Existence functiod to these records that are generating empty solves our problem.


Map after using logical existence functiod :












Result After Test Map and using Logical Existence :












What Logical Existence does ?

The logical functiod is used to determine whether the RecordField Element, or Field Attribute node that is linked to it exists in a particular input instance message. If functiod evaluates to true then destination schema node is generated otherwise not.


Using XSL Choose in inline XSLT in BizTalk mapper


We can use <xsl;choose> in BizTalk mapper using inline XSLT.
Scenario : Suppose if a XML is coming to BizTalk server and we have to check that if a customer is 'Premium' or 'Normal' or anything then we can use <xsl:choose> to check these conditions.

Source Schema :















Destination Schema :















Map:

In BizTalk Mapper we can add a scripting functiod and add the inline XSLT to the functiod.




















Inline XSLT :




<EmployeeDetail>
  <xsl:for-each select ="Data">
    <Details>
      <xsl:variable name="var:v1" select="EmployeeType/text()" />
      <xsl:choose>
        <xsl:when test="$var:v1 = 'Premium'">
          <Name>
            <xsl:value-of select="Employee_Name/text()"/>
          </Name>
        </xsl:when>
        <xsl:when test="$var:v1 = 'Normal'">
          <ID>
            <xsl:value-of select="EmployeeID/text()"/>
          </ID>
        </xsl:when>
        <xsl:otherwise>
          <Address>
            <xsl:value-of select="Address/text()"/>
          </Address>
        </xsl:otherwise>
      </xsl:choose>
    </Details>
  </xsl:for-each>
</EmployeeDetail>




Input XML:

Case 1:


<?xml version="1.0"?>
-<ns0:Employee xmlns:ns0="http://XSLT_Test.Source">
  -<Data>
    <Employee_Name>John</Employee_Name>
    <EmployeeType>Premium</EmployeeType>
    <EmployeeID>10</EmployeeID>
    <Address>44,Manhatton</Address>
    <PhoneNo>9986647474</PhoneNo>
  </Data>
</ns0:Employee>



Case 2:


<?xml version="1.0"?>
-<ns0:Employee xmlns:ns0="http://XSLT_Test.Source">
  -<Data>
    <Employee_Name>John</Employee_Name>
    <EmployeeType>Premium</EmployeeType>
    <EmployeeID>10</EmployeeID>
    <Address>44,Manhatton</Address>
    <PhoneNo>9986647474</PhoneNo>
  </Data>
</ns0:Employee>




Case 3:


<?xml version="1.0"?>
-<ns0:Employee xmlns:ns0="http://XSLT_Test.Source">
  -<Data>
    <Employee_Name>John</Employee_Name>
    <EmployeeType>Invalid</EmployeeType>
    <EmployeeID>10</EmployeeID>
    <Address>44,Manhatton</Address>
    <PhoneNo>9986647474</PhoneNo>
  </Data>
</ns0:Employee>





Test Map Results :

We can Test the map using "Test Map" and following are the results :

Case 1 :

<EmployeeDetail xmlns:ns0="http://XSLT_Test.Destination">
    <Details>

         <Name>John</Name>
       </Details>
   </EmployeeDetail>


Case 2 :

<EmployeeDetail xmlns:ns0="http://XSLT_Test.Destination">

   <Details>
      <ID>10</ID>
      </Details>
   </EmployeeDetail>

Case 3 :
  
     <EmployeeDetail xmlns:ns0="http://XSLT_Test.Destination">
        <Details>

   <Address>44,Manhatton</Address>
    </Details>
 </EmployeeDetail>


From above result we can see that how <xsl:choose> can be used to decide on the conditions.
When the input was a 'Premium' customer then the result was only 'Name' field.
    When the input was a 'Normal' customer then the result was only 'ID' field.
    When the input was a 'Invalid' customer then the result was only 'Address' field.



Using inline XSLT in BizTalk Map.


We can use inline XSLT in Biztalk maps for transformations. I'll be using inline XSLT and calling a simple C# class in the XSLT. For this we have to write XSLT in scripting functiod also write a class in inline c# of scripting functiod.

Below is the source schema used for map.












Destination Schema is :












Map goes like this :












XSLT goes like this :


<Output>
<xsl:for-each select = "Root">
<Desti>
<Name><xsl:value-of select = "Name/text()" />
</Name><ID><xsl:value-of select ="ID/text()"/>
</ID><xsl:variable name="var:v1" select="userCSharp:concatAddress(string(Name/text()) , string(Address/text()))" />
<Full_Address>
<xsl:value-of select ="$var:v1" />
</Full_Address>
<xsl:variable name="var:v2" select = "userCSharp:AddID (string (ID/text() ),string(Roll_No/text()))"/>
<Roll_No><xsl:value-of select = "$var:v2"/>
</Roll_No><xsl:if test="not(string(ID/text())=0)">
<Original_RollNo>
<xsl:value-of select ="ID/text()"/>
</Original_RollNo>
</xsl:if></Desti>
</xsl:for-each>
</Output> 


C# script goes like this :


public string concatAddress(string Name, string Address){

return Name + Address;}
public int AddID(int ID,int RollNo){

return ( ID + RollNo); }


In XSLT code I have called both these methods. Just droppping the inline C# functiod on mapper surface will work fine,also we don't have to connect this sfunctiod to any node in destination schema.