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