简体   繁体   中英

How to remove xmlns attribute of a node other than root in an XDocument?

Situation

I'm using XDocument to try and remove an xmlns="" attribute on the first inner node:

<Root xmlns="http://my.namespace">
    <Firstelement xmlns="">
        <RestOfTheDocument />
    </Firstelement>
</Root>

So what I want as a result is:

<Root xmlns="http://my.namespace">
    <Firstelement>
        <RestOfTheDocument />
    </Firstelement>
</Root>

Code

doc = XDocument.Load(XmlReader.Create(inStream));

XElement inner = doc.XPathSelectElement("/*/*[1]");
if (inner != null)
{
    inner.Attribute("xmlns").Remove();
}

MemoryStream outStream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(outStream);
doc.Save(writer); // <--- Exception occurs here

Problem

Upon trying to save the document, I get the following exception:

The prefix '' cannot be redefined from '' to ' http://my.namespace ' within the same start element tag.

What does this even mean and what can I do to remove that pesky xmlns="" ?

Notes

  • I do want to keep the root node's namespace
  • I only want that specific xmlns removed, there will be no other xmlns attributes in the document.

Update

I've tried using code inspired from answers on this question :

inner = new XElement(inner.Name.LocalName, inner.Elements());

When debugging, the xmlns attribute is gone from it but I get the same exception.

I think the code below is what you want. You need to put each element into the right namespace, and remove any xmlns='' attributes for the affected elements. The latter part is required as otherwise LINQ to XML basically tries to leave you with an element of

<!-- This would be invalid -->
<Firstelement xmlns="" xmlns="http://my.namespace">

Here's the code:

using System;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XDocument doc = XDocument.Load("test.xml");
        // All elements with an empty namespace...
        foreach (var node in doc.Root.Descendants()
                                .Where(n => n.Name.NamespaceName == ""))
        {
             // Remove the xmlns='' attribute. Note the use of
             // Attributes rather than Attribute, in case the
             // attribute doesn't exist (which it might not if we'd
             // created the document "manually" instead of loading
             // it from a file.)
             node.Attributes("xmlns").Remove();
             // Inherit the parent namespace instead
             node.Name = node.Parent.Name.Namespace + node.Name.LocalName;
        }
        Console.WriteLine(doc); // Or doc.Save(...)
    }
}

There is no need to 'remove' the empty xmlns attribute. The whole reason that the empty xmlns attrib is added is because the namespace of your childnodes is empty (= '') and therefore differ from your root node. Adding the same namespace to your childs as well will solve this 'side-effect'.

XNamespace xmlns = XNamespace.Get("http://my.namespace");

// wrong
var doc = new XElement(xmlns + "Root", new XElement("Firstelement"));

// gives:
<Root xmlns="http://my.namespace">
    <Firstelement xmlns="" />
</Root>

// right
var doc = new XElement(xmlns + "Root", new XElement(xmlns + "Firstelement"));

// gives:
<Root xmlns="http://my.namespace">
    <Firstelement />
</Root>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM