Connected Pawns

August 1, 2009

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

Filed under: BizTalk — Tags: , , , — mbrimble @ 9:54 pm

 

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&#8217; cannot contain child element ‘http://Blah.ContactDetails:Contact&#8217; 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 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>

About these ads

11 Comments »

  1. Bravo sir… you made my day!

    Comment by Chandu — March 18, 2010 @ 6:54 pm

  2. Hi,
    A quick quesiton on your sample, do you ignore the below error when validating the map to capture the xsl and xml file?

    error btm1010: The “Scripting” functoid has 0 input parameter(s), but 1 parameter(s) are expected.

    Comment by Chandu — March 18, 2010 @ 10:12 pm

    • Yes all you want is the xsl.

      Comment by mbrimble — March 19, 2010 @ 8:14 am

  3. Hi,

    Stephen’s jottings found a simple way to do this! Anyway many thks for your post!

    http://stephenomo.blogspot.com/2011/11/convert-xml-file-to-string-inside.html

    Comment by HelderSoares — January 17, 2012 @ 9:12 am

    • Added this as a change to my post on 27/2/2011. Did you read this?

      Comment by mbrimble — January 17, 2012 @ 7:50 pm

  4. Hey there just wanted to give you a quick heads up and let you
    know a few of the pictures aren’t loading correctly. I’m not sure
    why but I think its a linking issue. I’ve tried it in two different browsers and both show the same outcome.

    Comment by this comparison — October 17, 2012 @ 9:56 pm

    • I hae just checked the pictures and they seen Ok to me.

      Comment by mbrimble — November 4, 2012 @ 8:40 pm

  5. Hi

    I can’t thank you enough for this article.
    I’m not saying my final solution is better but I thought I’d mention it because it seemed simpler 
    Rather than adding a method to an assembly and having to GAC it (which I know gives you reusability and unit testability) I just placed a scripting functiod on my map containing the following c# –

    public string ToXmlString(XPathNodeIterator node)
    {
    return node.Current.OuterXml;
    }

    The c# functiod did not have an output (no line to a field in the output schema)

    I then added another scripting functiod to the map. This time I linked it to my output/destination node/element and set it to be an inline XSLT (not call template). I added this XSL to the functiod (BizTalkProcessResult being my target node) –

    I was pleased to see these two functiods solved my problems and meant that I didn’t have to resort to custom XSLTs therefore losing the benefits of the map designer. I had problems with XSLT call templates such as the following

    <![CDATA[

    ]]>

    Doing it this XSLT way seemed to result in losing namespace declarations on attributes, plus it seems more complicated to me. I just needed an exact copy of the source message as a string

    thanks again

    Paul

    Comment by Paul Nichols — April 10, 2013 @ 2:01 pm

  6. Hi

    I can’t thank you enough for this article.
    I’m not saying my final solution is better but I thought I’d mention it because it seemed simpler 
    Rather than adding a method to an assembly and having to GAC it (which I know gives you reusability and unit testability) I just placed a scripting functiod on my map containing the following c# –

    public string ToXmlString(XPathNodeIterator node)
    {
    return node.Current.OuterXml;
    }

    The c# functiod did not have an output (no line to a field in the output schema)

    I then added another scripting functiod to the map. This time I linked it to my output/destination node/element and set it to be an inline XSLT (not call template). I added this XSL to the functiod (BizTalkProcessResult being my target node) –

    <![CDATA[<

    ]]>

    I was pleased to see these two functiods solved my problems and meant that I didn’t have to resort to custom XSLTs therefore losing the benefits of the map designer. I had problems with XSLT call templates such as the following

    <![CDATA[

    <![CDATA[

    ]]>

    ]]>

    Doing it this XSLT way seemed to result in losing namespace declarations on attributes, plus it seems more complicated to me. I just needed an exact copy of the source message as a string

    thanks again

    Paul

    PS the CDATA tags above in my code examples where just so i could post this reply otherwise the xml was removed from the post

    Comment by Paul Nichols — April 10, 2013 @ 2:05 pm

  7. Hi

    I can’t thank you enough for this article.
    I’m not saying my final solution is better but I thought I’d mention it because it seemed simpler 
    Rather than adding a method to an assembly and having to GAC it (which I know gives you reusability and unit testability) I just placed a scripting functiod on my map containing the following c# –

    public string ToXmlString(XPathNodeIterator node)
    {
    return node.Current.OuterXml;
    }

    The c# functiod did not have an output (no line to a field in the output schema)

    I then added another scripting functiod to the map. This time I linked it to my output/destination node/element and set it to be an inline XSLT (not call template). I added this XSL to the functiod (BizTalkProcessResult being my target node) –

    <!–Uncomment the following

    –>

    I was pleased to see these two functiods solved my problems and meant that I didn’t have to resort to custom XSLTs therefore losing the benefits of the map designer. I had problems with XSLT call templates such as the following

    <![CDATA[

    ]]>

    –>

    Doing it this XSLT way seemed to result in losing namespace declarations on attributes, plus it seems more complicated to me. I just needed an exact copy of the source message as a string

    thanks again
    Paul

    Comment by Paul Nichols — April 10, 2013 @ 2:09 pm

  8. i was smart enough to solve this problem but not smart enough to post my solution without losing the xml sections of it!

    Comment by Paul Nichols — April 10, 2013 @ 2:10 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 92 other followers

%d bloggers like this: