web-dev-qa-db-ja.com

XDocumentのルート以外のノードのxmlns属性を削除するにはどうすればよいですか?

状況

XDocumentを使用して、xmlns=""最初のinnerノードの属性:

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

結果として私が望むのは:

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

コード

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

問題

ドキュメントを保存しようとすると、次の例外が発生します。

プレフィックス ''は、同じ開始要素タグ内で ''から ' http://my.namespace 'に再定義できません。

これはどういう意味ですか、その厄介なxmlns=""

ノート

  • ルートノードの名前空間を保持したい
  • 特定のxmlnsを削除するだけで、ドキュメントには他のxmlns属性はありません。

更新

この質問 の回答からヒントを得たコードを使用してみました。

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

デバッグすると、xmlns属性は削除されますが、同じ例外が発生します。

20
MarioDS

下のコードはあなたが望むものだと思います。各要素を正しい名前空間に入れる必要があります。and remove xmlns=''影響を受ける要素の属性。それ以外の場合、LINQ to XMLは基本的に次の要素を残そうとするため、後者の部分が必要です。

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

コードは次のとおりです。

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(...)
    }
}
34
Jon Skeet

空の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>
18
Andries