web-dev-qa-db-fra.com

Comment supprimer l'attribut xmlns d'un nœud autre que root dans un XDocument?

Situation

J'utilise XDocument pour essayer de supprimer un xmlns="" attribut sur le premier nœud interne :

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

Donc, ce que je veux en conséquence, c'est:

<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

Problème

En essayant d'enregistrer le document, j'obtiens l'exception suivante:

Le préfixe "" ne peut pas être redéfini de "" à " http: //my.namespace " dans la même balise d'élément de démarrage.

Qu'est-ce que cela signifie même et que puis-je faire pour supprimer ce satané xmlns=""?

Remarques

  • Je souhaite conserver l'espace de noms du nœud racine
  • Je veux seulement que ce xmlns spécifique soit supprimé, il n'y aura pas d'autres attributs xmlns dans le document.

Mise à jour

J'ai essayé d'utiliser du code inspiré des réponses sur cette question :

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

Lors du débogage, l'attribut xmlns a disparu mais j'obtiens la même exception.

20
MarioDS

Je pense que le code ci-dessous est ce que vous voulez. Vous devez mettre chaque élément dans le bon espace de noms, et supprimer tout xmlns='' attributs pour les éléments affectés. Cette dernière partie est requise car sinon LINQ to XML essaie essentiellement de vous laisser un élément de

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

Voici le 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

Il n'est pas nécessaire de "supprimer" l'attribut xmlns vide. La seule raison pour laquelle l'attribut xmlns vide est ajouté est que l'espace de noms de vos nœuds enfants est vide (= '') et diffère donc de votre nœud racine. L'ajout du même espace de noms à vos enfants résoudra également cet "effet secondaire".

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