How to remove all namespaces from XML with C#?
Well, here is the final answer. I have used great Jimmy idea (which unfortunately is not complete itself) and complete recursion function to work properly.
Based on interface:
string RemoveAllNamespaces(string xmlDocument);
I represent here final clean and universal C# solution for removing XML namespaces:
//Implemented based on interface, not part of algorithm
public static string RemoveAllNamespaces(string xmlDocument)
{
XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(xmlDocument));
return xmlDocumentWithoutNs.ToString();
}
//Core recursion function
private static XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
XElement xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
foreach (XAttribute attribute in xmlDocument.Attributes())
xElement.Add(attribute);
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
It's working 100%, but I have not tested it much so it may not cover some special cases... But it is good base to start.
Remove q1 and all namespaces from xml
The simplest way is to 'post-process' the XML:
var doc = XDocument.Parse(xml);
doc.Descendants().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
foreach (var element in doc.Descendants())
{
element.Name = element.Name.LocalName;
}
var xmlWithoutNamespaces = doc.ToString();
The other option (as you can't amend the source class XML attributes) is to implement a decorator for XmlWriter
that ignores all namespaces, but it's quite a large class so there'd be a lot of boilerplate delegation.
Linq to Xml : Remove namespace
As stated here
Based on interface:
string RemoveAllNamespaces(string xmlDocument);
I represent here final clean and universal C# solution for removing
XML namespaces://Implemented based on interface, not part of algorithm
public static string RemoveAllNamespaces(string xmlDocument)
{
XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(xmlDocument));
return xmlDocumentWithoutNs.ToString();
}
//Core recursion function
private static XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
XElement xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
foreach (XAttribute attribute in xmlDocument.Attributes())
xElement.Add(attribute);
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
Above solution still have two flase
- It ignores attributes
- It doesn't work with "mixed mode" elements
Here is another solution:
public static XElement RemoveAllNamespaces(XElement e)
{
return new XElement(e.Name.LocalName,
(from n in e.Nodes()
select ((n is XElement) ? RemoveAllNamespaces(n as XElement) : n)),
(e.HasAttributes) ?
(from a in e.Attributes()
where (!a.IsNamespaceDeclaration)
select new XAttribute(a.Name.LocalName, a.Value)) : null);
}
Sample code here.
C# - How to remove xmlns from XElement
I'd like to expand upon the existing answers. Specifically, I'd like to refer to a common use-case for removing namespaces from an XElement
, which is: to be able to use Linq queries in the usual way.
When a tag contains a namespace, one has to use this namespace as an XNamespace
on every Linq query (as explained in this answer), so that with the OP's xml, it would be:
XNamespace ns = "http://www.blablabla.com/bla";
var element = xelement.Descendants(ns + "retEvent")).Single();
But usually, we don't want to use this namespace every time. So we need to remove it.
Now, @octaviocc's suggestion does remove the namespace attribute from a given element. However, the element name still contains that namespace, so that the usual Linq queries won't work.
Console.WriteLine(xelement.Attributes().Count()); // prints 1
xelement.Attributes().Where( e => e.IsNamespaceDeclaration).Remove();
Console.WriteLine(xelement.Attributes().Count()); // prints 0
Console.WriteLine(xelement.Name.Namespace); // prints "http://www.blablabla.com/bla"
XNamespace ns = "http://www.blablabla.com/bla";
var element1 = xelement.Descendants(ns + "retEvent")).SingleOrDefault(); // works
var element2 = xelement.Descendants("retEvent")).SingleOrDefault(); // returns null
Thus, we need to use @Sam Shiles suggestion, but it can be simplified (no need for recursion):
private static void RemoveAllNamespaces(XElement xElement)
{
foreach (var node in xElement.DescendantsAndSelf())
{
node.Name = node.Name.LocalName;
}
}
And if one needs to use an XDocument
:
private static void RemoveAllNamespaces(XDocument xDoc)
{
foreach (var node in xDoc.Root.DescendantsAndSelf())
{
node.Name = node.Name.LocalName;
}
}
And now it works:
var element = xelement.Descendants("retEvent")).SingleOrDefault();
How to strip namespaces from Xml Document
Your problem is that you're removing the namespace prefix from the root element, but it's still being used to qualify the attributes themselves in the rest of the document. You want to strip namespaces out of the entire document first.
public static class XmlExtensions
{
public static void StripNamespace(this XDocument document)
{
if (document.Root == null) return;
foreach (var element in document.Root.DescendantsAndSelf())
{
element.Name = element.Name.LocalName;
element.ReplaceAttributes(GetAttributesWithoutNamespace(element));
}
}
static IEnumerable<XAttribute> GetAttributesWithoutNamespace(XElement xElement)
{
return xElement.Attributes()
.Where(x => !x.IsNamespaceDeclaration)
.Select(x => new XAttribute(x.Name.LocalName, x.Value));
}
}
Then simply:
XDocument xDoc = XDocument.Parse(xml);
xDoc.StripNamespace();
xDoc.Root.Add(new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance\\"));
xDoc.Root.Add(new XAttribute(XNamespace.Xmlns + "xsd", "http://www.w3.org/2001/XMLSchema\\"));
This produces the XML you were after.
Remove all nodes in a specified namespace from XML
Iterating through elements then through attributes seems not too hard to read :
var xml = @"<?xml version='1.0' encoding='UTF-8'?>
<root xmlns:test='urn:my-test-urn'>
<Item name='Item one'>
<test:AlternativeName>Another name</test:AlternativeName>
<Price test:Currency='GBP'>124.00</Price>
</Item>
</root>";
var doc = XDocument.Parse(xml);
XNamespace test = "urn:my-test-urn";
//get all elements in specific namespace and remove
doc.Descendants()
.Where(o => o.Name.Namespace == test)
.Remove();
//get all attributes in specific namespace and remove
doc.Descendants()
.Attributes()
.Where(o => o.Name.Namespace == test)
.Remove();
//print result
Console.WriteLine(doc.ToString());
output :
<root xmlns:test="urn:my-test-urn">
<Item name="Item one">
<Price>124.00</Price>
</Item>
</root>
Related Topics
Get List of Connected Usb Devices
Pass Array Parameter in Sqlcommand
Unity: Null While Making New Class Instance
Entity Framework - Include Multiple Levels of Properties
Metadataexception: Unable to Load the Specified Metadata Resource
Decimal Precision and Scale in Ef Code First
Calculate the Execution Time of a Method
Which .Net Dependency Injection Frameworks Are Worth Looking Into
How to Write a Simple Html.Dropdownlistfor()
A Generic Error Occurred in Gdi+, Jpeg Image to Memorystream
Splash Screen Waiting Until Thread Finishes
Replacing .Net Webbrowser Control With a Better Browser, Like Chrome
Multiline String Literal in C#
Why Can't I Define a Default Constructor For a Struct in .Net
Compare Two List≪T≫ Objects For Equality, Ignoring Order