it-swarm.dev

Como remover o atributo xmlns de um nó diferente da raiz em um XDocument?

Situação

Estou usando XDocument para tentar remover um xmlns="" atributo no primeiro nó interno :

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

Então, o que eu quero como resultado é:

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

Código

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

Problema

Ao tentar salvar o documento, recebo a seguinte exceção:

O prefixo '' não pode ser redefinido de '' para ' http: //my.namespace ' dentro da mesma tag do elemento inicial.

O que isso significa e o que posso fazer para remover esse incômodo xmlns=""?

Notas

  • Quero manter o espaço para nome do nó raiz
  • Eu quero apenas que xmlns específico seja removido, não haverá outros atributos xmlns no documento.

Atualizar

Eu tentei usar código inspirado nas respostas em esta pergunta :

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

Ao depurar, o atributo xmlns desapareceu, mas recebo a mesma exceção.

20
MarioDS

Eu acho que o código abaixo é o que você deseja. Você precisa colocar cada elemento no espaço para nome correto, e remover qualquer xmlns='' atributos para os elementos afetados. A última parte é necessária, caso contrário, o LINQ to XML basicamente tenta deixá-lo com um elemento de

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

Aqui está o código:

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

Não há necessidade de 'remover' o atributo xmlns vazio. Todo o motivo pelo qual o atributo xmlns vazio foi adicionado é porque o espaço para nome dos nós filhos está vazio (= '') e, portanto, difere do nó raiz. Adicionar o mesmo espaço para nome aos seus filhos também resolverá esse 'efeito colateral'.

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