Removing Xml Namespace in a pipeline component

Listen with webReader
Published 07 January 08 11:11 PM | Johan Hedberg

Richard Hallgren recently blogged about how to remove Xml namespaces from Xml documents, as has Kirk Allen Evans earlier here and here. While the latter writes from a general .NET and ASP.NET perspective Richard's post is from a BizTalk perspective and in his post he asks for alternative ways, other then the ways he is presenting, of doing it. 

The root issue is how do I turn

<ns0:Blah xmlns:ns0="http://RemoveXmlNamespace.BTS.BlahMessage">

into

<Blah>


First of all, let me just say that I understand namespace and I don't think they should be removed if at all avoidable. This is not my first choice of a solution, as it probably isn't for anyone working with BizTalk. The fact remains though that in some cases it still turns out to be necessary. My option of doing this would then be by using a pipeline component and the classes available to us from Microsoft.BizTalk.Streaming.dll. My main reason for this is performance. I would really hate to have to keep either the source document or the resulting document in memory using XmlDocument and MemoryStream like the XslTransform pipeline component sample from the BizTalk Server 2006 SDK does. I'm pretty certain that particular sample can be enhanced using XPathDocument, XslCompiledTransform and VirtualStream (to keep down the impact on memory) but it still isn't as good if your only purpose is removing the namespace. That sample can however do many other things that my option can't, since it does an XslTransform and this doesn't.

So using the streaming classes in general and XmlTranslatorStream in particular we can override some of it's methods to create a streaming xsl transformation doing what we want. The resulting code is suprisingly simple. Here is the Execute method:

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(
    IPipelineContext pContext, 
    Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
{
    pInMsg.BodyPart.Data = new XmlNamespaceRemoverStream(
        pInMsg.BodyPart.GetOriginalDataStream());
    return pInMsg;
}

And here is the class that does the actual work (although as you can see it doesn't really do much):

public class XmlNamespaceRemoverStream : XmlTranslatorStream
{
    protected override void TranslateStartElement(
        string prefix, string localName, string nsURI)
    {
        base.TranslateStartElement(null, localName, null);
    }

    protected override void TranslateAttribute()
    {
        if (this.m_reader.Prefix != "xmlns")
            base.TranslateAttribute();
    }

    public XmlNamespaceRemoverStream(Stream input)
        : base(new XmlTextReader(input), Encoding.Default)
    { }
}

This sample is available for download: RemoveXmlNamespacePipeline.zip.

Comments

# Kirk Allen Evans said on January 8, 2008 12:22 AM:

That's sweet!  Nice solution, and easy to comprehend as well (much more so than the XmlNoNamespaceWriter, which took me 2 times to get right).

# Richard Hallgren said on January 8, 2008 03:41 PM:

Nice! Keep up the good work!

# Big Kev is still excited said on April 28, 2008 10:13 PM:

In the Part 4 I covered the XmlTranslatorStream in detail, explaining how it provides powerful coupling

#   Removing namespace from outgoing messages by .RICHARD said on June 17, 2008 08:29 AM:

Pingback from  &nbsp; Removing namespace from outgoing messages&nbsp;by&nbsp;.RICHARD

# Be Logical - writings by Johan Hedberg said on January 6, 2009 09:00 AM:

So, a year passed. Year-end statistics are always fun. However I really need to make sure we have additional

# KattyBlackyard said on June 15, 2009 09:07 AM:

Hi, gr8 post thanks for posting. Information is useful!

# Nema said on June 10, 2010 02:03 PM:

Hi, thanks for a great post. Do you know if there is any way to keep the xml declaration wich seems to be removed?

# Albert said on October 4, 2010 09:44 PM:

Just use ESB Toolkit RemoveNamespacePipelineComponent. It´s easy and there is no need to write a line of code.

# Johan Hedberg said on October 4, 2010 10:17 PM:

@Albert You could. At the time of writing this post ESB Tookit didn't exist and the early release of the ESB Guidance wasn't as easy and as supported an option as it is today.

@Nema I am not directly aware of the problem you are describing, though I would look to the Xml Assembler for adding an Xml declaration.

# Fernando Pires said on March 26, 2011 01:34 PM:

How to add the xml declaration

protected override void TranslateXmlDeclaration(string target, string value)

       {

           this.m_writer.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");

       }

# Fernando Pires said on March 26, 2011 01:48 PM:

Better solution to keeping existing declaration

protected override void TranslateXmlDeclaration(string target, string value)

       {

           this.m_writer.WriteProcessingInstruction(this.m_reader.Name, this.m_reader.Value);

       }

# Johan Hedberg said on April 1, 2011 09:12 AM:

Thanks you for the addition Fernando

# Meik Cremer said on April 19, 2011 11:38 AM:

Thanks Johan and Fernando - this saved my day.

# Leonid Ganeline said on December 7, 2011 04:54 PM:

Great finding!

What about Micrsoft.BizTalk.Component.NamespaceTranslatorStream

class? Can we use it? MSDN does a little to describe anything regarding those classes :(

# Johan Hedberg said on December 11, 2011 12:02 PM:

Hi Leonid,

Yes. The NamespaceTranslatorStream is derived from XmlTranslatorStream and it does the job of converting one namespace into another. In early 2008 I simply wasn't aware that class existed ;)

I am both a fan of having descriptive components that help describe the solution, ie a RemoveNamespaceComponent to remove a namespace, while at the same time I like to keep custom code to a minimum.

If a more dynamic component is what you want you are probably also better of prividing a custom implementation of the XmlTranslatorStream that can translate more then one namespace, as in the NamespaceTranslatorStream, while processing the stream so you wont have to chain a bunch of them if that is a requirement.

# Leonid Ganeline said on March 22, 2012 06:48 PM:

Johan,

I'm using your code right now. Works as charm! It is so SUPER-DUPPER simple! Thanks a lot!

# Kwinten said on April 4, 2012 10:25 AM:

Johan,

I converted your example to Biztalk2010 and XML declaration is being removed but namespaces not...did I forgot something?

# Peter Lindgren said on August 23, 2012 08:27 AM:

Hi, I also added an override to TranslateAttributeValue:

protected override void TranslateAttributeValue(string prefix, string localName, string nsURI, string val)

{

   string newValue = val.Remove(0, val.IndexOf(':') + 1);

   base.TranslateAttributeValue(null, localName, nsURI, newValue);

}

This Blog

News

    Messenger

    Twitter Updates

      Follow me on twitter

      Visitors

      Feedburner Subscribers

      Locations of visitors to this page

      Disclaimer

      All material is provided AS IS voiding any thinkable or unthinkable effect it might have for any use whatsoever. There... is that clear enough ;)

      Pages

    Syndication