Como serializar um objeto para XML sem obter xmlns = “…”?

109

Existe uma maneira de serializar um objeto em .NET sem que os namespaces XML também sejam serializados automaticamente? Parece que, por padrão, o .NET acredita que os namespaces XSI e XSD devem ser incluídos, mas eu não os quero lá.

Wes P
fonte

Respostas:

142

Ahh ... deixa pra lá. É sempre a busca depois que a pergunta é feita que produz a resposta. Meu objeto que está sendo serializado está obje já foi definido. Adicionar um XMLSerializerNamespace com um único namespace vazio à coleção resolve o problema.

Em VB assim:

Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")

Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True

Using ms As New MemoryStream(), _
    sw As XmlWriter = XmlWriter.Create(ms, settings), _
    sr As New StreamReader(ms)
xs.Serialize(sw, obj, ns)
ms.Position = 0
Console.WriteLine(sr.ReadToEnd())
End Using

em C # assim:

//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

//Add an empty namespace and empty value
ns.Add("", "");

//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);

//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);
Wes P
fonte
12
Eu tentei isso em VB, os atributos xsi e xsd desapareceram, mas atributos como xmlns: q12 =, d3p1: type e xmlns: d3p1 apareceram.
MiddleKay
16
Tentei a versão C # e ela removeu o xsi e o xsd, mas adicionou um prefixo q1: a todos os nomes de tag XML, o que eu não queria. Parece que o exemplo C # está incompleto, referenciando myXmlTextWriter que suponho que precise ser inicializado da mesma maneira que o exemplo VB.
redtetraedro
1
@redtetrahedron Você encontrou uma maneira de se livrar dessa q1porcaria?
esmagamento de
Consulte a resposta stackoverflow.com/questions/31946240/… , se q1 adicionado como namespace em branco
aniruddha
20

Se você quiser se livrar do extra xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"e xmlns:xsd="http://www.w3.org/2001/XMLSchema", mas ainda manter seu próprio namespace xmlns="http://schemas.YourCompany.com/YourSchema/", use o mesmo código acima, exceto por esta mudança simples:

//  Add lib namespace with empty prefix  
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   
Ali B
fonte
13

Se você deseja remover o namespace, você também pode remover a versão, para evitar a pesquisa, adicionei essa funcionalidade para que o código abaixo faça as duas coisas.

Também o envolvi em um método genérico, pois estou criando arquivos xml muito grandes para serializar na memória, portanto, dividi meu arquivo de saída e o serializei em "pedaços" menores:

    public static string XmlSerialize<T>(T entity) where T : class
    {
        // removes version
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;

        XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
        using (StringWriter sw = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(sw, settings))
        {
            // removes namespace
            var xmlns = new XmlSerializerNamespaces();
            xmlns.Add(string.Empty, string.Empty);

            xsSubmit.Serialize(writer, entity, xmlns);
            return sw.ToString(); // Your XML
        }
    }
D34th
fonte
Cuidado, o StringWriterpadrão é a codificação UTF-16, que pode levar a problemas de desserialização no fluxo. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Isso lança uma exceção porque a declaração afirma que é UTF-16, enquanto o conteúdo foi realmente escrito como UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan
Para contornar isso e ainda usar XmlReader, você pode usar var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);O verdadeiro usará o BOM se encontrado, caso contrário, o padrão fornecido por você.
Tyler StandishMan
9

Eu sugiro esta classe auxiliar:

public static class Xml
{
    #region Fields

    private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
    private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});

    #endregion

    #region Methods

    public static string Serialize(object obj)
    {
        if (obj == null)
        {
            return null;
        }

        return DoSerialize(obj);
    }

    private static string DoSerialize(object obj)
    {
        using (var ms = new MemoryStream())
        using (var writer = XmlWriter.Create(ms, WriterSettings))
        {
            var serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, Namespaces);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public static T Deserialize<T>(string data)
        where T : class
    {
        if (string.IsNullOrEmpty(data))
        {
            return null;
        }

        return DoDeserialize<T>(data);
    }

    private static T DoDeserialize<T>(string data) where T : class
    {
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
        {
            var serializer = new XmlSerializer(typeof (T));
            return (T) serializer.Deserialize(ms);
        }
    }

    #endregion
}

:)

Maziar Taheri
fonte
ótima resposta :) também adicionei esta linha stream.Position = 0; e retornou todo o fluxo em minha solução .. funcionou como esperado - todas as tags de desaceleração foram removidas
ymz
Adicionar o argumento de namespaces à chamada do serializador sozinho funcionou para mim remover os namespaces padrão. Escrever em new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})vez de new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})é uma maneira intencionalmente mais clara de codificá-lo, na minha opinião.
Suncat2000
5

Se você não conseguir se livrar de atributos xmlns extras para cada elemento, ao serializar para xml a partir de classes geradas (por exemplo: quando xsd.exe foi usado), então você tem algo como:

<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />

então eu compartilharia com você o que funcionou para mim (uma mistura de respostas anteriores e o que encontrei aqui )

defina explicitamente todos os seus xmlns diferentes da seguinte maneira:

Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
xmlns.Add("three",  "urn:names:specification:schema:xsd:three")

em seguida, passe para o serializar

serializer.Serialize(writer, object, xmlns);

vocêterá os três namespaces declarados no elemento raiz e não precisa mais ser gerado nos outros elementos que serão prefixados de acordo

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...
vinjenzo
fonte
0
        XmlWriterSettings settings = new XmlWriterSettings
        {
            OmitXmlDeclaration = true
        };

        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");

        StringBuilder sb = new StringBuilder();

        XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            xs.Serialize(xw, model, ns);
            xw.Flush();
            return sb.ToString();
        }
Taurus999able
fonte