Category nameļ¼šXSLT

Difference in mapping between BizTalk 2010 and 2013

December 16, 2013 / Comments Off on Difference in mapping between BizTalk 2010 and 2013

Difference in mapping 2010
versus 2013

 

Artifacts description

In a
BizTalk 2010 project we have a function that passes the current XmlNode as an
XpathNodeIterator to a helper component. In BizTalk 2010 the map look like
this:

Note that
we are using custom XSLT here. The content of the XSLT is show below :

<?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 userCSharp
ScriptNS0″ version=”1.0″ xmlns:ns0=”http://TestMap.SomeSchema” xmlns:userCSharp=”http://schemas.microsoft.com/BizTalk/2003/userCSharp” xmlns:ScriptNS0=”http://schemas.microsoft.com/BizTalk/2003/ScriptNS0″>
  <xsl:output omit-xml-declaration=“yes” method=”xml” version=”1.0″ />
  <xsl:template match=“/”>
    <xsl:apply-templates select=“/ns0:Root” />
  </xsl:template>
  <xsl:template match=“/ns0:Root”>
    <ns0:Root>
      <xsl:for-each select=“RepeatingNode”>
        <xsl:variable name=“var:v1″ select=”userCSharp:StringTrimRight(string(SomeNode1/text()))” />
        <xsl:variable name=“var:v3″ select=”userCSharp:StringTrimRight(string(SomeNode2/text()))” />
        <RepeatingNode>
          <xsl:variable name=“var:v2” select=”ScriptNS0:WriteNode(string($var:v1) , .)” />
          <SomeNode1>
            <xsl:value-of select=“$var:v2” />
          </SomeNode1>
          <xsl:variable name=“var:v4” select=”ScriptNS0:WriteNode(string($var:v3) , .)” />
          <SomeNode2>
            <xsl:value-of select=“$var:v4” />
          </SomeNode2>
        </RepeatingNode>
      </xsl:for-each>
    </ns0:Root>
  </xsl:template>
  <msxsl:script language=“C#” implements-prefix=”userCSharp”><![CDATA[

public
string StringTrimRight(string str)
{
       if (str == null)
       {
               return “”;
       }
       return str.TrimEnd(null);
}
]]></msxsl:script>
</xsl:stylesheet>

 

The content
of the Extension XML is shown below :

<ExtensionObjects>
  <ExtensionObject Namespace=“http://schemas.microsoft.com/BizTalk/2003/ScriptNS0″ AssemblyName=”MapHelper,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=94092251336a29ea” ClassName=”MapHelper.mapHelperClass” />
</ExtensionObjects>

 

The code of
function in the Helperclass is shown below :

using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Xml.XPath;
using
System.Xml;

 

namespace
MapHelper
{
   public class mapHelperClass
   {

        public static bool
WriteNode(string somedata,XPathNodeIterator node)
        {
           XPathNavigator
xpn = node.Current;
           XmlDocument
xdoc = new XmlDocument();
           xdoc.LoadXml(xpn.OuterXml);
           System.Diagnostics.Trace.WriteLine(“In
function ->”+ xdoc.OuterXml);
            return true;
       }
   }
}

Expected behavior BizTalk
2010

If we run
this map in BizTalk 2010 and watch for the output in Debug View we get the
expected output

Also the
map test succeeds in BizTalk 2010. As shown below:

Invoking
component…
F:ProjectsTestMapTestMapSomeMap.btm:
The compilation is using the CustomXslt and CustomExtensionXml tags to generate
the output.  The map content is ignored.
TestMap
used the following file:
<file:///C:UsersAdministratorAppDataLocalTempinputfile.xml> as
input to the map.
Test Map
success for map file F:ProjectsTestMapTestMapSomeMap.btm. The output is
stored in the following file:
<file:///C:UsersAdministratorAppDataLocalTemp_MapDataTestMapSomeMap_output.xml>
Component invocation succeeded.


Observed behavior BizTalk
2013

If we run
this in BizTalk 2013 we get the following output.

Invoking component…

C:ProjectsTestMap2013TestMapTestMapSomeMap.btm:
The compilation is using the CustomXslt and CustomExtensionXml tags to generate
the output.  The map content is ignored.
TestMap used the following file:
<file:///C:UsersAdministratorAppDataLocalTempinputfile.xml> as
input to the map.
C:ProjectsTestMap2013TestMapTestMapSomeMap.btm:
error btm1050: XSL transform error: Unable to write output instance to the
following
<file:///C:UsersAdministratorAppDataLocalTemp_MapDataTestMapSomeMap_output.xml>.

Exception
has been thrown by the target of an invocation. An error occurred during a call
to extension function ‘WriteNode’. See InnerException for a complete
description of the error. Enumeration has not started. Call MoveNext.
Test Map failure for map file <file:///C:ProjectsTestMap2013TestMapTestMapSomeMap.btm>.
The output is stored in the following file:
<file:///C:UsersAdministratorAppDataLocalTemp_MapDataTestMapSomeMap_output.xml>
Component invocation succeeded.

So the map failed because the behavior of the compiled xslt is different from the interpreted xslt.

Desired Behavior

The behavior
should be the same as in BizTalk 2010.

 

You can find the test project in the attachment

XSLT Distinct another way to determine distinct in XSLT 1.0

February 17, 2011 / Comments Off on XSLT Distinct another way to determine distinct in XSLT 1.0

I had a requirement to map a buyer only if it was the same buyer throughout the entire document.
The reason for this was that in the source document the buyer was defined in a sub sub sub node of a document and in the destination it occurred only once.
So I ended up with several choices.

  • Only map the first buyer
  • Don’t map
  • Only map if they were the same throughout the entire document

For sure the first option would be a bad thing.
The second option would work for all parties involved (it’s an optional element in the output of the map) but the parties really want their buyer information if it’s there.
The third option seemed the best solution. I quickly googled on XSLT and distinct and there were some results. So I told the customer implementing a distinct wouldn’t be too hard. (it already existed in XSLT).
(I wish I looked a bit harder, cause then I would have seen that the distinct function of XSLT comes with XSLT 2.0 and sadly BizTalk is still using XSLT1.0)

After some thinking I got the following solution for this problem.

  1. Perform a count of the number of buyers in a document
  2. Get the first buyer (buyer is mandatory in the input document)
  3. Perform a count of the numbers of buyers where buyer != buyer found in step2

If the number in step 3 is 0 then we know all the buyers are the same. Below is the XSLT I used to perform this different distinct approach.

<xsl:template name=”Buyerparty_DocTemplate”>
  <xsl:param name=”var1″ />
  <xsl:param name=”var2″ />
  <xsl:param name=”dbg” />
  <xsl:variable name=”buyers” select=”count(/s0:Request/GeleverdePartij/LeveringsBericht/Levering[*]/Ladingdrager[*]/Goederen[*]/Koper/kop_gln)” />
  <xsl:variable name=”firstBuyer” select=”/s0:Request/GeleverdePartij/LeveringsBericht/Levering[1]/Ladingdrager[1]/Goederen[1]/Koper/kop_gln” />
  <xsl:variable name=”otherBuyers” select=”count(/s0:Request/GeleverdePartij/LeveringsBericht/Levering[*]/Ladingdrager[*]/Goederen[*]/Koper[not(kop_gln=$firstBuyer)])” />
  <xsl:if test=”$dbg=1″>
    <xsl:element name=”BuyerInfo”>
      <xsl:element name=”TotalBuyers”>
        <xsl:value-of select=”$buyers” />
      </xsl:element>
      <xsl:element name=”FirstBuyer”>
        <xsl:value-of select=”$firstBuyer” />
      </xsl:element>
      <xsl:element name=”OtherBuyers”>
        <xsl:value-of select=”$otherBuyers” />
      </xsl:element>
    </xsl:element>
  </xsl:if>
  <xsl:if test=”$otherBuyers=0″>
    <xsl:if test=”string-length($firstBuyer) > 0″>
      <xsl:element name=”BuyerParty”>
        <xsl:element name=”PrimaryID”>
          <xsl:value-of select=”$firstBuyer” />
        </xsl:element>
        <xsl:element name=”schemeID”>
          <xsl:value-of select=”$var1″ />
        </xsl:element>
        <xsl:element name=”schemeAgencyName”>
          <xsl:value-of select=”$var2″ />
        </xsl:element>
      </xsl:element>
    </xsl:if>
  </xsl:if>
</xsl:template>

Using XSLT Templates in a map (reminder@self)

August 16, 2010 / Comments Off on Using XSLT Templates in a map (reminder@self)

We all know that using XSLT inside a map can be very usefull to do stuff that’s very hard to do with the mapper itself.
Sometimes using XSLT it is the only way things can be done. I find myself struggeling each time to figure out how specific tasks work with XSLT.

That’s why I write this post. So I wont have to figure it all out again the next time i need this functionality….
Below is some code used in an ‘Inline XSLT Call Template’ to calculate the number of segments in a message (UNT) and the message Message Reference number.

The input CurrentIndex is retrieved from an Iteration functoid that returns the current index of the transaction. This index is used to retrieve the correct values for the UNT segment of that transaction
( I am using the batched EDI schema’s).

<xsl:template name=UNTTemplate>

  <xsl:param name=currentIndex />

  <xsl:variable name=sum01 select=count(/s2:Request/INTERCHANGE/UNB) />

  <xsl:variable name=sum02 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/UNH) />

  <xsl:variable name=sum03 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/BGM) />

  <xsl:variable name=sum04 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/DTM) />

  <xsl:variable name=sum05 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/NAD) />

  <xsl:variable name=sum06 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN) />

  <xsl:variable name=sum07 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/DTM) />

  <xsl:variable name=sum08 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/NAD) />

  <xsl:variable name=sum09 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/RFF) />

  <xsl:variable name=sum10 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/QTY) />

  <xsl:variable name=sum11 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/PRI) />

  <xsl:variable name=sum12 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/IMD) />

  <xsl:variable name=sum13 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/IMD/PRICE_INFORMATION) />

  <xsl:variable name=sum14 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/PAC) />

  <xsl:variable name=sum15 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/PAC/PRI) />

  <xsl:variable name=sum16 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/EQD) />

  <xsl:variable name=sum17 select=count(/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/LIN/EQD/EQN) />

  <xsl:variable name=unt18  select=/s2:Request/INTERCHANGE/TRANSACTION[position()=$currentIndex]/UNH/MESSAGE_REFERENCE_NUMBER />

  <xsl:variable name=totalCount select=$sum01 + $sum02 + $sum03 + $sum04 + $sum05+ $sum06 + $sum07 + $sum08 + $sum09 + $sum10 + $sum11 + $sum12 + $sum13 + $sum14 + $sum15+ $sum16 + $sum17 />

  <xsl:element name=UNT>

    <xsl:element name=UNT1>

      <xsl:value-of select=$totalCount />

    </xsl:element>

    <xsl:element name=UNT2>

      <xsl:value-of  select=$unt18 />

    </xsl:element>

  </xsl:element>

</xsl:template>

 

  • Recent Posts
  • Recent Comments
  • Archives
  • Categories
  • Meta