10

How can I remove the xmlns namespace from a XElement?

I tried: attributes.remove, xElement.Name.NameSpace.Remove(0), etc, etc. No success.

My xml:

<event xmlns="http://www.blablabla.com/bla" version="1.00">
  <retEvent version="1.00">
  </retEvent>
</event>

How can I accomplish this?

Damini Suthar
  • 1,470
  • 2
  • 14
  • 43
Eduardo
  • 693
  • 3
  • 9
  • 21
  • 3
    You can't easily do that; that means rewriting every name to not have a namespace. What problem are you trying to solve? You should use namespaces consistently. – SLaks Nov 09 '16 at 22:51
  • And how are you getting the XML to start with? Is your code creating it, or is it XML you're reading from elsewhere? More information would be very helpful here. – Jon Skeet Nov 09 '16 at 22:52
  • SLaks, the problem is that my schema is not validating when the namespace is present in some nodes. – Eduardo Nov 10 '16 at 11:29
  • I'm reading a varchar from database Jon. First I parse it to a XDocument e after I parse it to XElement "XDocument.Descendants().Where(p => p.Name.LocalName == "event").FirstOrDefault()" – Eduardo Nov 10 '16 at 11:31

3 Answers3

12

@octaviocc's answer did not work for me because xelement.Attributes() was empty, it wasn't returning the namespace as an attribute.

The following will remove the declaration in your case:

element.Name = element.Name.LocalName;

If you want to do it recursively for your element and all child elements use the following:

    private static void RemoveAllNamespaces(XElement element)
    {
        element.Name = element.Name.LocalName;

        foreach (var node in element.DescendantNodes())
        {
            var xElement = node as XElement;
            if (xElement != null)
            {
                RemoveAllNamespaces(xElement);
            }
        }
    } 
OfirD
  • 9,442
  • 5
  • 47
  • 90
Sam Shiles
  • 10,529
  • 9
  • 60
  • 72
  • 3
    Kept getting the error: The prefix '' cannot be redefined from '' to within the same start element tag. just used the simple form for one element in an already existing document, no matter even when I tried to copy the element separetly from the document , and then use "element.Name = element.Name.LocalName;" and attach it to document, kept getting errors, only the other answer worked after I tried every damn thing I could find in the internet – jimjim Jun 05 '19 at 07:24
  • 1
    Arf, it's xml...there is a reason the world has moved on :) – Sam Shiles Jun 05 '19 at 12:37
10

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();
OfirD
  • 9,442
  • 5
  • 47
  • 90
9

You could use IsNamespaceDeclaration to detect which attribute is a namespace

xelement.Attributes()
        .Where( e => e.IsNamespaceDeclaration)
        .Remove();
ocuenca
  • 38,548
  • 11
  • 89
  • 102