Portierung von Maps mit mehreren Eingangsnachrichten (multi-source mapping)

12.07.2018

Einer unserer Kunden, der aktuell BizTalk Server 2010 einsetzt, wollte gerne seine bestehenden Mappings ohne große Änderungen zu dem Azure Integration Account migrieren um sie in Azure Logic Apps zu verwenden.

Bei den meisten Maps war die Migration ohne weiteres möglich in dem man einfach das generierte Xslt hochlud.

Bei anderen Mappings mit mehreren Eingangsnachrichten war dies leider nicht möglich, da die Transform XML Aktion nur eine Eingangsnachricht unterstützt.

<?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 s0 s2 s1 userCSharp"

version="1.0"

xmlns:s0="http://MultiSourceMapping/InputMessage1"

xmlns:s2="http://schemas.microsoft.com/BizTalk/2003/aggschema"

xmlns:s1="http://MultiSourceMapping/InputMessage2"

xmlns:ns0="http://MultiSourceMapping/OutMessage"

xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp">

  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />

  <xsl:template match="/">

    <xsl:apply-templates select="/s2:Root" />

  </xsl:template>

  <xsl:template match="/s2:Root">

   <ns0:Result>

      <FromInputMessage1>

        <xsl:value-of select="InputMessagePart_0/s0:Element/text()" />

      </FromInputMessage1>

      <FromInputMessage2>

        <xsl:value-of select="InputMessagePart_1/s1:OtherElement/text()" />

      </FromInputMessage2>    

    </ns0:Result>

  </xsl:template>

</xsl:stylesheet>

 

Die erste Möglichkeit, die uns einfiel, war das envelope Schema, welches BizTalk für uns automatisch generiert, manuell anzulegen.

 

<ns0:Root xmlns:ns0=\"http://schemas.microsoft.com/BizTalk/2003/aggschema\">     

<InputMessagePart_0>@{body('Get_blob_content')}</InputMessagePart_0> <InputMessagePart_1>@{body('Get_blob_content_2')}</InputMessagePart_1>

 

</ns0:Root>

 

 

 

Damit war es ohne weiteres möglich die vorhanden Mapping zu übernehmen. Das Konzept war jedoch nicht Jedem verständlich, somit das Ziel des Kunden, alles klar und einfach zu halten, nicht erreicht.

Dann fiel uns eine zweite Möglichkeit ein, die zwar eine kleine Anpassung an der Map nötig machte, aber viel klarer machte, was hier eigentlich passiert: Wir geben der Map die beiden Nachrichten als String-Parameter und konvertieren sie zu einen XPathNodeIterator Objekt.

Die wenigen Änderungen, die an der Map nötig waren, sind nachfolgend gelb hinterlegt.

<?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 s0 s2 s1 userCSharp"

version="1.0"

xmlns:s0="http://MultiSourceMapping/InputMessage1"

xmlns:s2="http://schemas.microsoft.com/BizTalk/2003/aggschema"

xmlns:s1="http://MultiSourceMapping/InputMessage2"

xmlns:ns0="http://MultiSourceMapping/OutSchema"

xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp">

 

  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />

<xsl:param name ="InputMessage1" />

<xsl:param name ="InputMessage2" />


  <xsl:variable name ='InputMessagePart_0'
select='userCSharp:ConvertXMLStringToXPathNodeIterator($InputMessage1)' /
<xsl:variable name ='InputMessagePart_1' select
='userCSharp:ConvertXMLStringToXPathNodeIterator($InputMessage2)' />

<xsl:template match="/">

    <xsl:apply-templates select="/s2:Root" />

  </xsl:template>

  <xsl:template match="/s2:Root">

   <ns0:Result>

      <FromInputMessage1>

        <xsl:value-of select="$InputMessagePart_0/s0:Element/text()" />

      </FromInputMessage1>

      <FromInputMessage2>

        <xsl:value-of select="$InputMessagePart_1/s1:OtherElement/text()" />

      </FromInputMessage2>    

    </ns0:Result>

  </xsl:template>

  <msxsl:script language="C#" implements-prefix="userCSharp">

  <msxsl:using namespace="System.IO" />

  <msxsl:using namespace="System.Xml.XPath" />

  <![CDATA[

  public XPathNodeIterator ConvertXMLStringToXPathNodeIterator (string XML)

  {

      using (StringReader sr = new StringReader(XML))

      {

          XPathDocument xpd = new XPathDocument(sr);

          XPathNavigator xpn = xpd.CreateNavigator();

          return xpn.Select("/");

      }

  }

  ]]>

</msxsl:script>

</xsl:stylesheet>

 

Die Transform XML Aktion sieht dann folgendermaßen aus:

"Transform_XML": {

                "inputs": {

                    "content": "<ns0:Root xmlns:ns0='http://schemas.microsoft.com/BizTalk/2003/aggschema' />",

                    "integrationAccount": {

                        "map": {

                            "name": "MultiSourceMapping"

                        }

                    },

                    "xsltParameters": {

                        "InMessage1": "@{body('Get_blob_content')}",

                        "InMessage2": "@{body('Get_blob_content_2')}"

                    }

                },

                "runAfter": {

                    "Get_blob_content_2": [

                        "Succeeded"

                    ]

                },

                "type": "Xslt"

 

            }

 

 

 

 

 

Mit der zweiten Lösung war auch unser Kunde sehr zufrieden, da sie gut zu pflegen ist und nur wenige Änderungen an den Maps benötigt, was den Test- und Entwicklungsaufwand minimiert.

QUIBIQ Berlin

 

 

 

zurück