web-dev-qa-db-de.com

Wie entferne ich das xmlns-Attribut eines anderen Knotens als root in einem XDocument?

Situation

Ich verwende XDocument, um zu versuchen, ein xmlns="" - Attribut auf dem ersten inneren Knoten zu entfernen:

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

Was ich als Ergebnis haben möchte, ist:

<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

Beim Versuch, das Dokument zu speichern, wird die folgende Ausnahme angezeigt:

Das Präfix '' kann nicht von '' nach ' http: //my.namespace ' innerhalb desselben Startelement-Tags neu definiert werden.

Was bedeutet das überhaupt und was kann ich tun, um diesen lästigen xmlns="" Zu entfernen?

Anmerkungen

  • Ich möchte den Namespace des Root-Knotens beibehalten
  • Ich möchte nur dieses bestimmte xmlns entfernen, es werden keine anderen xmlns Attribute im Dokument vorhanden sein.

Aktualisieren

Ich habe versucht, Code zu verwenden, der von den Antworten auf diese Frage inspiriert wurde:

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

Beim Debuggen wird das xmlns -Attribut nicht mehr angezeigt, aber ich erhalte dieselbe Ausnahme.

20
MarioDS

Ich denke, der folgende Code ist das, was Sie wollen. Sie müssen jedes Element in den richtigen Namespace setzen, nd entfernen Sie alle xmlns='' - Attribute für die betroffenen Elemente. Letzterer Teil wird benötigt, da LINQ to XML sonst grundsätzlich versucht, Ihnen ein Element von zu hinterlassen

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

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

Das leere xmlns-Attribut muss nicht 'entfernt' werden. Der ganze Grund, warum das leere xmlns-Attribut hinzugefügt wird, ist, dass der Namespace Ihrer untergeordneten Knoten leer ist (= '') und sich daher von Ihrem Stammknoten unterscheidet. Wenn Sie auch Ihren Kindern denselben Namespace hinzufügen, wird dieser Nebeneffekt behoben.

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