How to copy the entire node to element of string type in a map

Posted: August 1, 2009  |  Categories: BizTalk Uncategorized

I wanted to copy the entire Contact node in the map below to the ContactDetails element of type string.

XML2Text

I could have done this in an orchestration by assigning the node to an XmlDocument variable and then assigning the XmlDocument.InnerText to a distinguished field in the outbound message but I wanted to do this in map  because I plan to put the map on the outbound port and not in an orchestration.

My  first try almost worked. I used a scripting functoid with this Inline XSLT.

<!–MassCopy alternative that does not copy the namespace.–>

<ns1:ContactDetails

<xsl:copy-of select=”*[local-name()=’Contact’]”/>

</ns1:ContactDetails>

This almost works but I get this error on validation;

The element ‘http://schemas.microsoft.com/Sql/2008/05/TypedProcedures/dbo:ContactDetails’ cannot contain child element ‘http://Blah.ContactDetails:Contact’ because the parent element’s content model is text only.

The problem here is that it’s copying the node structure to the outbound message and not mapping the node structure to a string.

#1 Azure Monitoring Platform

So i have tried two solutions from posts by Greg Forsythe namely http://www.biztalkgurus.com/forums/t/12350.aspx and http://connectedpawns.wordpress.com/2008/10/08/call-a-net-assembly-from-custom-xslt/ ( I had to use my blog because the original link seems to be broken). I have decided to record how I did it because Greg’s instructions are very brief and it took me a while to work out what to do.

The first step is to create a helper class and deploy it to the GAC .

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

namespace CopyXML2TextNodeBTSDemo.Utility
{
    public class Utilities
    {
        public static string ConvertNodeToXmlString(XPathNodeIterator node)

        {      nodes.MoveNext();

               return node.Current.OuterXml;

         }

    }
}

Secondly reference this assembly in the BizTalk map project.

Add a scripting functoid to the map , choose external assembly as the scripting type with the values shown below and connect it to the a field in the outbound schema.

scriptingfunctoid

Validate the map to generate a xsl file and a Custom extension XML file. The output is shown below

Invoking component.….CopyXML2TextNodeBTSDemo.Maps\SubmitContactDetails2XMLdatafieldasTEXT.btm: The compilation is using the CustomXslt and CustomExtensionXml tags to generate the output.  The map content is ignored.
….CopyXML2TextNodeBTSDemo.Maps\SubmitContactDetails2XMLdatafieldasTEXT.btm: The output XSLT is stored in the following file: <file:///C:\..\_MapData\SubmitContactDetails2XMLdatafieldasTEXT.xsl>
  ….\SubmitContactDetails2XMLdatafieldasTEXT.btm: The Extension Object XML is stored in the following file: <file:///C:\..\_MapData\SubmitContactDetails2XMLdatafieldasTEXT_extxml.xml>
Component invocation succeeded.

Save both files and add them to the BizTalk map project.

Change the map to use a the generated xsl file as the custom XSLT and the Extension Object XML file as shown below.

customXSLT

Edit xsl file like so;

<?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 ScriptNS0″ version=”1.0″ xmlns:ns0=”http://CopyXML2TextNodeBTSDemo.XMLdatafieldasTEXT” xmlns:s0=”http://CopyXML2TextNodeBTSDemo.SubmitContactDetails” 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=”/s0:SubmitContactDetails” />
    </xsl:template>
    <xsl:template match=”/s0:SubmitContactDetails”>
        <ns0:ContainsXMLfieldasText>
            <ContactId>
                <xsl:value-of select=”ContactId/text()” />
            </ContactId>
            <xsl:apply-templates  select=”Contact”/>
        </ns0:ContainsXMLfieldasText>
    </xsl:template>
    <xsl:template  match=”Contact”>
        <xsl:variable name=”var:v1″ select=”ScriptNS0:ConvertNodeToXmlString(.)” />
        <ContactDetails>
            <xsl:value-of select=”$var:v1″ />
        </ContactDetails>
    </xsl:template>
</xsl:stylesheet>

Now if you test the map you get the desired output. Whew!!

—————————————————————————– Added 27/2/2011

Another way to do this is use an inline XSLT template in a map something like this

<!–Uncomment the following xslt for a sample Xslt Call Template that creates a Field element whose value is the concatenatation of the two inputs. Change the number of parameters of this template to be equal to the number of inputs connected to this functoid.–>

<xsl:template name=”called-template”>
  <xsl:param name=”param1″ />
  <xsl:element name=”ns0:Message”>
    <xsl:text disable-output-escaping=”yes”>&lt;![CDATA[</xsl:text>
    <xsl:call-template name=”identity” />
    <xsl:text disable-output-escaping=”yes”>]]&gt;</xsl:text>
  </xsl:element>
</xsl:template>
<xsl:template name=”identity” match=”@*|node()”>
  <xsl:copy>
    <xsl:apply-templates select=”@*|node()” />
  </xsl:copy>
</xsl:template>

#1 Azure Monitoring Platform
turbo360

Back to Top