.NET
XmlDocument
XML
xmlns attribute
programming tips

How to prevent blank xmlns attributes in output from .NET's XmlDocument?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When manipulating XML in .NET using XmlDocument, blank xmlns="" attributes often appear on elements that are moved, cloned, or created without specifying the correct namespace. This happens because .NET resets the namespace to empty when an element's namespace does not match its parent's. The fix is to always pass the correct namespace URI when creating elements with CreateElement(), use XmlNamespaceManager consistently, or switch to XDocument (LINQ to XML) which handles namespaces more naturally.

The Problem

csharp
1using System.Xml;
2
3var doc = new XmlDocument();
4doc.LoadXml(@"<root xmlns='http://example.com/ns'>
5  <parent>
6    <child>value</child>
7  </parent>
8</root>");
9
10// Create a new element WITHOUT specifying the namespace
11var newElement = doc.CreateElement("added");
12newElement.InnerText = "new value";
13doc.DocumentElement.FirstChild.AppendChild(newElement);
14
15Console.WriteLine(doc.OuterXml);
16// Output: <root xmlns="http://example.com/ns">
17//           <parent>
18//             <child>value</child>
19//             <added xmlns="">new value</added>   ← blank xmlns!
20//           </parent>
21//         </root>

The xmlns="" appears because CreateElement("added") creates an element in the empty namespace, which differs from the parent's http://example.com/ns namespace. .NET emits the explicit xmlns="" to indicate this mismatch.

Fix 1: Specify the Namespace in CreateElement

csharp
1var doc = new XmlDocument();
2doc.LoadXml(@"<root xmlns='http://example.com/ns'>
3  <parent><child>value</child></parent>
4</root>");
5
6string ns = doc.DocumentElement.NamespaceURI;
7
8// Pass prefix, localName, and namespaceURI
9var newElement = doc.CreateElement("", "added", ns);
10newElement.InnerText = "new value";
11doc.DocumentElement.FirstChild.AppendChild(newElement);
12
13Console.WriteLine(doc.OuterXml);
14// <root xmlns="http://example.com/ns">
15//   <parent><child>value</child><added>new value</added></parent>
16// </root>
17// No blank xmlns!

The three-argument overload CreateElement(prefix, localName, namespaceURI) ensures the new element inherits the correct namespace.

Fix 2: Use XmlNamespaceManager

csharp
1var doc = new XmlDocument();
2var nsMgr = new XmlNamespaceManager(doc.NameTable);
3nsMgr.AddNamespace("ns", "http://example.com/ns");
4
5doc.LoadXml(@"<root xmlns='http://example.com/ns'>
6  <parent><child>value</child></parent>
7</root>");
8
9// Select nodes using the namespace manager
10var parent = doc.SelectSingleNode("//ns:parent", nsMgr);
11
12// Create element in the correct namespace
13var newElement = doc.CreateElement("added", "http://example.com/ns");
14newElement.InnerText = "new value";
15parent.AppendChild(newElement);

Fix 3: Use XDocument (LINQ to XML)

XDocument handles namespaces more cleanly than XmlDocument:

csharp
1using System.Xml.Linq;
2
3XNamespace ns = "http://example.com/ns";
4
5var doc = XDocument.Parse(@"<root xmlns='http://example.com/ns'>
6  <parent><child>value</child></parent>
7</root>");
8
9// XNamespace + string automatically creates elements in the correct namespace
10doc.Root.Element(ns + "parent").Add(
11    new XElement(ns + "added", "new value")
12);
13
14Console.WriteLine(doc);
15// <root xmlns="http://example.com/ns">
16//   <parent><child>value</child><added>new value</added></parent>
17// </root>

The XNamespace + "elementName" pattern makes namespace handling explicit and prevents blank xmlns attributes.

Fix 4: Removing Blank xmlns After the Fact

If you must work with existing code that produces blank xmlns attributes:

csharp
1using System.Xml;
2using System.Text.RegularExpressions;
3
4// Quick fix — remove blank xmlns from the output string
5string xml = doc.OuterXml;
6xml = xml.Replace(" xmlns=\"\"", "");
7
8// Better — recursively fix namespaces in the DOM
9void FixNamespaces(XmlNode node, string targetNs)
10{
11    if (node is XmlElement element && element.NamespaceURI == "")
12    {
13        // Recreate element with correct namespace
14        var replacement = node.OwnerDocument.CreateElement(
15            element.Prefix, element.LocalName, targetNs);
16
17        // Copy attributes
18        foreach (XmlAttribute attr in element.Attributes)
19        {
20            if (attr.Name != "xmlns")
21                replacement.SetAttribute(attr.Name, attr.Value);
22        }
23
24        // Move children
25        while (element.HasChildNodes)
26            replacement.AppendChild(element.FirstChild);
27
28        element.ParentNode.ReplaceChild(replacement, element);
29        node = replacement;
30    }
31
32    foreach (XmlNode child in node.ChildNodes)
33        FixNamespaces(child, targetNs);
34}
35
36FixNamespaces(doc.DocumentElement, "http://example.com/ns");

Working with Prefixed Namespaces

csharp
1var doc = new XmlDocument();
2doc.LoadXml(@"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
3  <soap:Body/>
4</soap:Envelope>");
5
6string soapNs = "http://schemas.xmlsoap.org/soap/envelope/";
7
8// Create element with prefix and namespace
9var header = doc.CreateElement("soap", "Header", soapNs);
10doc.DocumentElement.PrependChild(header);
11
12// Create element in a different namespace with its own prefix
13var custom = doc.CreateElement("app", "Data", "http://myapp.com/ns");
14custom.InnerText = "payload";
15header.AppendChild(custom);
16
17Console.WriteLine(doc.OuterXml);
18// <soap:Envelope xmlns:soap="...">
19//   <soap:Header><app:Data xmlns:app="http://myapp.com/ns">payload</app:Data></soap:Header>
20//   <soap:Body/>
21// </soap:Envelope>

Common Pitfalls

  • Using the one-argument CreateElement overload: doc.CreateElement("name") creates an element in the empty namespace. When appended to a node in a non-empty namespace, .NET adds xmlns="" to explicitly declare the mismatch. Always use the three-argument overload with the correct namespace URI.
  • Copying nodes between documents with different namespaces: ImportNode preserves the source element's namespace. If the source has no namespace and the target does, the imported node gets xmlns="". After importing, recreate the element in the target namespace.
  • String-replacing xmlns="" in the output: While xml.Replace(" xmlns=\"\"", "") removes the attribute from the string, it changes the document's semantics — elements that were intentionally in no namespace now appear to be in the parent's namespace. Only use this if you know all elements should share the same namespace.
  • Forgetting XmlNamespaceManager for XPath queries: SelectSingleNode("//parent") returns null when parent is in a namespace. You must register the namespace with XmlNamespaceManager and use a prefix in the XPath expression (//ns:parent).
  • Mixing XmlDocument and XDocument in the same codebase: Converting between XmlDocument and XDocument (via XmlReader) can reintroduce namespace issues. Pick one API and use it consistently. XDocument is generally preferred for new code due to cleaner namespace handling.

Summary

  • Blank xmlns="" appears when an element's namespace does not match its parent's
  • Always pass the namespace URI to CreateElement(prefix, localName, namespaceURI)
  • Use XDocument (LINQ to XML) instead of XmlDocument for cleaner namespace handling
  • Use XmlNamespaceManager for XPath queries on namespaced documents
  • Avoid string-replacing xmlns="" from output — it changes document semantics
  • When cloning or importing nodes, recreate them in the target namespace to prevent blank xmlns

Course illustration
Course illustration

All Rights Reserved.