April 10, 2013 at 4:08 PM

In an XSLT mapping I wanted to convert the node with its child nodes to a node with attributes. 
I noticed that the source schema contained more than 60 child nodes and most of them could be optional. The transform of this mapping would result in a big piece of code for some logic that perhaps could be made in a better way.

This process could be optimized by creating the attributes in a dynamic way. 

For illustration, I am using this small piece of XML:

<Contact>
	<Name>Reception</Name>
	<Phone>+32 9 247 32 65</Phone>
	<Mobile>+32 475 36 45 78</Mobile>
	<Fax>+32 9 247 32 66</Fax>
	<Email>reception@company.be</Email>
</Contact>

This is the desired output:

<Contact Name='Reception' Phone='+32 9 247 32 65' Mobile='+32 475 36 45 78' Fax='+32 9 247 32 66' Email='reception@company.be' />

The Problem

I am looping through each child node with the query Contact/* (there is no namespace for simplicity reasons). The function name() is able to give the name of the node. I store this name in the variable $attributeName, for later usage.  When we know the name of the current node, this should be easy to create an attribute dynamically:

<Contact>
    <xsl:for-each select="Contact/*">
            <xsl:variable name="attributeName" select="name(.)" />
            <xsl:attribute name="$attributeName">
              <xsl:value-of select="'value'"/>
            </xsl:attribute>
         </xsl:for-each>
     </xsl:for-each>
</Contact>


Although, it is impossible to define special characters in the name parameter of the attribute definition.
Visual studio gave me the error “the ‘$’ character, hexadecimal value 0x24, cannot be included in a name.”  

 

The Solution

The name argument is not able to perform a query or do some piece of logic. This problem can be solved by working with attribute value templates. Attribute value templates will evaluate the expression and convert the resulting object to a string.

I replaced $attributeName with {$attributeName}

This is the final result:

<Contact>
    <xsl:for-each select="Contact/*">
            <xsl:variable name="attributeName" select="name(.)" />
            <xsl:attribute name="{$attributeName}">
              <xsl:value-of select="'value'"/>
            </xsl:attribute>
         </xsl:for-each>
     </xsl:for-each>
</Contact>

 More information about attribute value templates can be found on the website of W3C.

Additional Notes

The same trick can be used to create elements in a dynamic way in XSLT or for using variables in arguments.
Note that when the source schema will be changed and some child nodes are added, this mapping will also add those attributes, even if this is unknown by the destination schema. This can be positive or negative.

Posted in: Schemas | XML | XSLT

Tags: , ,


February 27, 2013 at 3:37 PM

One of the most asked change requests seems to be changing a part of a schema accompanying the modification of a mapping. Since a mapping from BizTalk can be made in the BizTalk mapper or in XSLT, it is always a bit of a surprise, how difficult this can be. It is interesting how the translation of The BizTalk mapper is done under the hood and how we can improve the performance. In this article I will concentrate  on the cumulative concatenate functoid found when working with the BizTalk mapper.

 

Project sample

An external schema contains a report about orders that have been processed. Each order line contains a validation code.
In our internal schema, we would like to use one node to know if the whole order has been processed or not. We can solve this by using the looper functoid, but in this case I will use the Cumulative concatenate functoid. 

 

The BizTalk mapper 

First we cumulate all the status values using a cumulative concatenate, afterwards, a find functoid will tell us if there is a status "NOK" (not ok) is present. Then we will determinate depending on the index if the status will end up in a true or false. This is a piece of cake.
 

 

 

The change

The change regarding this mapping, which should now be extended, the external schema can now have multiple statuses that tell us if a line has not been processed. ("NOK","NIS", "NA").  I won't implement this change, but I will concentrate in how to keep this mapping clean. 

 

Using an external xslt file

I will use an external XSLT schema for applying this change. It seems to be that if we will use another few functoids, our mapping will become a big mess. I simply generated an XSLT  from the existing mapping by right clicking the map in the solution explorer and selecting "Validate map". BizTalk will output two links, one of them will be the XSLT file. Save this file to disk and and refer from the mapping property "Custom XSLT Path" to the external XSLT file.


The first thing that strikes me is the fact that this XSLT file is nearly unreadable, or at least difficult to understand.

Under the hood, BizTalk is using at least one variable for each functoid you use. Since we cannot change the values of a variable in XSLT , BizTalk uses a script block with inline c# code at the bottom of the document for cumulating each value of the node Status.

 

 This is the generated code for the IsValid node. 

 

<xsl:variable name="var:v1"
select="userCSharp:InitCumulativeConcat(0)" /> 

Initialize the Cumulative array: The 0 refers to the fact that this is the first cumulative concatenation we are using in our mapping. This is the Key for our cumulative concatenation function. On that way, we are able to reuse the c# code multiple times again.

     

<xsl:for-each select="/s0:ExtOrderReport/Lines/Line">
        <xsl:variable name="var:v2" select="userCSharp:AddToCumulativeConcat(0,string(Status/text()),'1000')" />
</xsl:for-each>

Loop for each node we would like to concatenate, and give the value to the function "AddToCumulativeConcat". Note that we also use the 0 here.

      

<xsl:variable name="var:v3" select="userCSharp:GetCumulativeConcat(0)" />

Ask to the c# code to get all our values (again with the key 0)

    

<xsl:variable name="var:v4" select="userCSharp:StringFind(string($var:v3) , 'NOK')" />

Find a "NOK" value and returns an index result.
 

<xsl:variable name="var:v5" select="userCSharp:IsValidOrder(string($var:v4))" />
<IsValid>
	<xsl:value-of select="$var:v5" />
</IsValid>

Call our internal c# code to decide if this order is valid or not. 

 

Optimalizations

This seems to be a lot of code, for such a piece of logic, isn't it?

We might could manual optimize this, for performance reasons: 

 

<xsl:variable name="var:v1" select="userCSharp:InitCumulativeConcat(0)" />    
  <xsl:for-each select="/s0:ExtOrderReport/Lines/Line/Status"> 
      <xsl:variable name="var:v2" select="userCSharp:AddToCumulativeConcat(0,string(text()),'1000')" />   
   </xsl:for-each> 
     <xsl:variable name="var:v3" select="userCSharp:GetCumulativeConcat(0)" />    
  <IsValid>       
 <xsl:value-of select="not(contains($var:v3,'NOK'))" />  
    </IsValid>

 

I limited the for-each function only to the node we need, in that way, we only need to loop this node, not the whole line node.

I replaced the c# search function by the build in XSLT search function, since built-in functions are always faster than loading custom c# code.

After that, I limited the variables were possible. 

 

XML profiling

After this manually intervention, I would like to know what the result is of my improvements.

 

Visual studio offers by default XML profiling. When comparing these results, I could say that we did an improvement of nearly 50%

 

  

Conclusions

For long term maintenance reasons it is smarter to write your own xslt, and not use the built-in BTM (BizTalk mapper).

It's always possible to convert convert a BTM to an XSLT.

The BTM might be fast for easy mappings, but even for this, BTM will always generate a less readable and less performance XSLT file.

You can manually improve the mapping speed by yourself.


January 14, 2013 at 3:16 PM

Lately I came across a weird exception while building a BizTalk project with Team Foundation Server.  Let’s have a look.

 

The error

Although the build succeeded locally, we got this error while building our BizTalk project with TFS:

FlatFileSchema.xsd.cs: The type or namespace name '<ContextPropertyName>' could not be found in the global namespace (are you missing an assembly reference?)

 

The troubleshooting

After some try/error, we discovered that the error only occurred when building a BizTalk project in TFS that contains a flat file schema, using property promotion.   The first reflex was to compare the installed software on our local development machine and the Team Foundation Server.

  • Local machine: Full BizTalk 2010 Installation
  • TFS server: BizTalk 2010 Build Component

 

 

The solution

The solution was to install also the Developer Tools and SDK on the TFS server.  Although MSDN states that the Build Component should be sufficient.  This extra installation adds “Developer Tools\Schema Editor Extensions” to the BizTalk folder.  This is apparently needed for building flat files schemas that use property promotion.

Posted in: BizTalk | General | Schemas | TFS

Tags: ,


January 4, 2013 at 2:47 PM

A week ago, I had a problem with a Flat File Schema in BizTalk 2010. I thought I was doing everything right, but I forgot one important thing.

Below you can find the flat file we have to create a schema for.

N John      Smith    
A Fakestreet 123      New York            USA      
A Fakestreet 123      Newark              USA      
N Mathieu   Vermote  
A Fakestreet 123      Ghent               Belgium   
A Fakestreet 123      Roeselare           Belgium   
N Jane      Doe      
A Fakestreet 123      Los Angeles         USA      
A Fakestreet 123      Santa Cruz          USA      
A Fakestreet 123      San Francisco       USA      
N Jack      Doe      
N Jake      Doe         
A Fakestreet 123      Miami               USA   
A Fakestreet 123      Fort Lauderdale     USA   

So we have two type of lines, a name-line (starts with N) and a address-line (starts with A).

In the schema there should be a sequence with N and A repeating and A can occur 0 to many times.

 

So I made a schema looking like this:

image

The minOccurs and maxOccurs set to this:

N: 0 – 1

A: 0 – unbounded

The Tag Identifier is also set to ‘N ‘ for element Name and to ‘A ‘ for the element Address.

 

When I try to ‘Validate Instance’ in Visual Studio I get the error:

Unexpected data found while looking for: ‘A ‘

 

The solution to this error was to set the Parser Optimization to Complexity.

image

 

When the Parser Optimization is set to ‘speed’, which is the default value, the schema is optimized to decrease the parsing time. This is no problem for the most flat files, but for complex flat files it can be a problem.

So setting the value to ‘complexity’ can help your flat file schema parse complex flat files.

 

More info about the Parse Optimization property on MSDN: http://msdn.microsoft.com/en-us/library/aa578137.aspx

Posted in: BizTalk | Schemas

Tags:


November 14, 2012 at 4:43 PM

It’s a good practice to have some XML validation in your BizTalk integration flows.  It prevents you of sending mal-formatted messages to back-end systems and it also gives you the opportunity to validate incoming messages.  In the BizTalk toolbox, you have two standard pipeline components that can perform this XML validation.  Let’s have a look...

 

XML Disassembler (or XML Assembler)

The default configuration of the XML Disassembler will not perform any kind of XML validation on the message


If you want to enable XML validation on the XML Disassembler you need to set Validate document structure to True and explicitly set the Document schema(s) that need to be validated. Compared to the specified Documents schema(s):
- If the processed message has the same TargetNamespace#RootNodeName combination, XML validation will be performed

- If the processed message has another TargetNamespace#RootNodeName combination, an exception will be thrown (can’t recognize the data)

 

    image


XML Validator

The default configuration of the XML Validator will already perform XML validation. How? It retrieves the XML definition from the BizTalkMgmtDb, at run-time, using the TargetNamespace#RootNodeName combination.

-   If a matching schema is found, XML validation will be performed on the processed message

-   If no matching schema is found, the XML Validator will throw an exception (cannot retrieve document specification)


You can also explicitly specify at design-time the Document schema(s).  Compared to the specified Documents schema(s):

-   If the processed message has the same TargetNamespace#RootNodeName combination, XML validation will be performed

-   If the processed message has another TargetNamespace#RootNodeName combination, no XML validation will be performed


    image

 

Conclusion

You see a different behavior when comparing the components, especially when specifying Document schema(s). Depending on your needs, you can choose the appropriate setup.  I mostly opt for the combination of the XML Disassembler and XML Validator, both with their default configuration.  It has the advantage that you don’t need to configure anything at design-time.  They work together in this way:

-   The XML Disassembler is responsible for retrieving the BTS.MessageType, promoting context properties and debatching

-   The XML Validator will validate all messages, deciding at run-time which schema to use

Posted in: BizTalk | General | Schemas | XML

Tags:


October 30, 2012 at 3:01 PM

It’s a common practice to reuse schemas / types within your BizTalk solution.  Lately, I’ve encountered an issue regarding this.  Here you can find a simplified example and a solution to the problem.

 

Assume you have two reusable schemas (no dependencies between them):

-   http://schemas.codit.eu/common#Address

-   http://schemas.codit.eu/common#ContactInformation

 

Now you want to create a “Person’ schema in the http://schemas.codit.eu namespace, by reusing the previous schemas.

-   First you need to import the Address schema

-   Secondly you need to import also the ContactInformation schema.  This results in the error:

 
 The namespace of the schema you are trying to add clashes with one of the namespaces already declared.  Please choose another schema.

 image

 

Although, in XSD this is not a limitation.  So I’ve tried to work around the BizTalk Schema Editor and opened the XSD as an XML file.  I’ve manually added the XSD import of the ContractInformation schema:

 

image

 

After this workaround, I’ve opened the schema again with the BizTalk Schema Editor, without any errors.  It just seems to be a limitation of the BizTalk Schema Editor.

 

image

Posted in: BizTalk | General | Schemas

Tags: