16

I use .NET XML technologies quite extensively on my work. One of the things the I like very much is the XSLT engine, more precisely the extensibility of it. However there one little piece which keeps being a source of annoyance. Nothing major or something we can't live with but it is preventing us from producing the beautiful XML we would like to produce.

One of the things we do is transform nodes inline and importing nodes from one XML document to another.

Sadly , when you save nodes to an XmlTextWriter (actually whatever XmlWriter.Create(Stream) returns), the namespace definitions get all thrown in there, regardless of it is necessary (previously defined) or not. You get kind of the following xml:

<root xmlns:abx="http://bladibla">  
     <abx:child id="A">  
         <grandchild id="B">
             <abx:grandgrandchild xmlns:abx="http://bladibla" />  
         </grandchild>  
     </abx:child>  
</root>

Does anyone have a suggestion as to how to convince .NET to be efficient about its namespace definitions?

PS. As an added bonus I would like to override the default namespace, changing it as I write a node.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Boaz
  • 25,331
  • 21
  • 69
  • 77

3 Answers3

17

Use this code:

using (var writer = XmlWriter.Create("file.xml"))
{
    const string Ns = "http://bladibla";
    const string Prefix = "abx";

    writer.WriteStartDocument();

    writer.WriteStartElement("root");

    // set root namespace
    writer.WriteAttributeString("xmlns", Prefix, null, Ns);

    writer.WriteStartElement(Prefix, "child", Ns);
    writer.WriteAttributeString("id", "A");

    writer.WriteStartElement("grandchild");
    writer.WriteAttributeString("id", "B");

    writer.WriteElementString(Prefix, "grandgrandchild", Ns, null);

    // grandchild
    writer.WriteEndElement();
    // child
    writer.WriteEndElement();
    // root
    writer.WriteEndElement();

    writer.WriteEndDocument();
}

This code produced desired output:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:abx="http://bladibla">
  <abx:child id="A">
    <grandchild id="B">
      <abx:grandgrandchild />
    </grandchild>
  </abx:child>
</root>
Kirill Polishchuk
  • 54,804
  • 11
  • 122
  • 125
  • 4
    @polish: odds? What do you mean? The point is that people copy/paste our examples, and nobody should be using `new XmlTextWriter` as of .NET 2.0. – John Saunders Jun 26 '11 at 17:03
  • Yes, this works. I've been writing a lot of similar tests and cannot reproduce the behavior when using the writer directly. I think the problem only comes up in XSLT. – harpo Jun 27 '11 at 15:48
  • @polishchuk, you're right. I thought it happened automatically on expiration. I will follow up with some code when I get around to reproducing the problem. – harpo Jun 28 '11 at 05:32
  • 2
    @KirillPolishchuk When I use `writer.WriteAttributeString("xmlns", Prefix, null, Ns);` I get error: `The 'xmlns' attribute is bound to the reserved namespace 'http://www.w3.org/2000/xmlns/` any idea? using powershell – Mohemmad K Apr 16 '14 at 07:18
2

Did you try this?

Dim settings = New XmlWriterSettings With {.Indent = True,
                                          .NamespaceHandling = NamespaceHandling.OmitDuplicates,
                                          .OmitXmlDeclaration = True}
Dim s As New MemoryStream
Using writer = XmlWriter.Create(s, settings)
    ...
End Using

Interesting is the 'NamespaceHandling.OmitDuplicates'

habakuk
  • 2,712
  • 2
  • 28
  • 47
  • It is interesting. I'm in .NET 2.0, though. – harpo Jun 27 '11 at 15:46
  • @harpo: It is .Net 2.0 (see http://msdn.microsoft.com/de-de/library/ms162617%28v=vs.80%29.aspx) – habakuk Jun 28 '11 at 12:21
  • `XmlWriterSettings` is, but the `NamespaceHandling` property is not. http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.namespacehandling%28v=VS.100%29.aspx – harpo Jun 28 '11 at 16:33
1

I'm not sure this is what you're looking for, but you can use this kind of code when you start writing to the Xml stream:

myWriter.WriteAttributeString("xmlns", "abx", null, "http://bladibla");

The XmlWriter should remember it and not rewrite it anymore. It may not be 100% bulletproof, but it works most of the time.

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • It should, but it doesn't. Just to keep my foot out of my mouth, though I will double-check now. – harpo Jun 21 '11 at 23:16