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

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.
So i have tried two solutions from posts by Greg Forsyth 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)
{ 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.

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.

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!!