如何在XDocument中删除除root之外的节点的xmlns属性

Mar*_*oDS 20 .net c# xml linq-to-xml xml-namespaces

情况

我正在XDocument尝试删除xmlns=""第一个内部节点上的属性:

<Root xmlns="http://my.namespace">
    <Firstelement xmlns="">
        <RestOfTheDocument />
    </Firstelement>
</Root>
Run Code Online (Sandbox Code Playgroud)

所以我想要的结果是:

<Root xmlns="http://my.namespace">
    <Firstelement>
        <RestOfTheDocument />
    </Firstelement>
</Root>
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

问题

在尝试保存文档时,我得到以下异常:

在同一个start元素标记内,前缀''不能从''重新定义为' http://my.namespace '.

这甚至意味着什么,我该怎么做才能消除那些麻烦xmlns=""

笔记

  • 我确实想保留根节点的命名空间
  • 我只希望xmlns删除特定xmlns的文件,文件中没有其他属性.

更新

我尝试过使用这个问题的答案启发的代码:

inner = new XElement(inner.Name.LocalName, inner.Elements());
Run Code Online (Sandbox Code Playgroud)

调试时,该xmlns属性已从中消失,但我得到了相同的异常.

Jon*_*eet 35

我认为下面的代码就是你想要的.您需要将每个元素放入正确的命名空间,删除xmlns=''受影响元素的所有属性.后一部分是必需的,否则LINQ to XML基本上试图给你留下一个元素

<!-- This would be invalid -->
<Firstelement xmlns="" xmlns="http://my.namespace">
Run Code Online (Sandbox Code Playgroud)

这是代码:

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(...)
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*ies 18

无需"删除"空的xmlns属性.添加空xmlns attrib的全部原因是因为子节点的命名空间为空(=''),因此与根节点不同.为孩子添加相同的命名空间也可以解决这种"副作用".

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>
Run Code Online (Sandbox Code Playgroud)

  • 尽管Jon Skeet的回答直接解决了这个问题,但是这个方法避免了在创建xml后迭代遍历所有节点,而是在创建xml时阻止创建xmlns empty属性.在我看来哪种感觉更好. (6认同)
  • Tnx,这有帮助。此解决方案是关于防止而不是删除 ns (2认同)