Come serializzare un oggetto in XML senza ottenere xmlns = "..."?


109

C'è un modo per serializzare un oggetto in .NET senza che anche gli spazi dei nomi XML vengano serializzati automaticamente? Sembra che per impostazione predefinita .NET creda che gli spazi dei nomi XSI e XSD dovrebbero essere inclusi, ma non li voglio lì.

Risposte:


142

Ahh ... non importa. È sempre la ricerca dopo che la domanda è stata posta che fornisce la risposta. Il mio oggetto che viene serializzato è objed è già stato definito. L'aggiunta di un XMLSerializerNamespace con un singolo spazio dei nomi vuoto alla raccolta fa il trucco.

In VB come questo:

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

in C # come questo:

//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);

12
Ho provato questo in VB, gli attributi xsi e xsd sono scomparsi ma sono comparsi attributi come xmlns: q12 =, d3p1: type e xmlns: d3p1.
MiddleKay

16
Ho provato la versione C # e ha rimosso xsi e xsd ma ha aggiunto un prefisso di q1: a tutti i nomi dei tag XML, cosa che non volevo. Sembra che l'esempio C # sia incompleto, facendo riferimento a myXmlTextWriter che presumo debba essere inizializzato allo stesso modo dell'esempio VB.
redtetrahedron

1
@redtetrahedron Hai trovato un modo per sbarazzarti della q1merda?
schiacciare l'

Fare riferimento alla risposta stackoverflow.com/questions/31946240/… , se q1 aggiunto come spazio dei nomi vuoto
aniruddha

20

Se vuoi sbarazzarti dell'extra xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"e xmlns:xsd="http://www.w3.org/2001/XMLSchema", ma mantenere il tuo spazio dei nomi xmlns="http://schemas.YourCompany.com/YourSchema/", usa lo stesso codice di cui sopra tranne che per questa semplice modifica:

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

13

Se si desidera rimuovere lo spazio dei nomi, è possibile rimuovere anche la versione, per risparmiare la ricerca ho aggiunto quella funzionalità, quindi il codice seguente farà entrambe le cose.

L'ho anche inserito in un metodo generico poiché sto creando file xml molto grandi che sono troppo grandi per essere serializzati in memoria, quindi ho suddiviso il file di output e serializzato in "blocchi" più piccoli:

    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
        }
    }

Attenzione, il StringWritervalore predefinito è la codifica UTF-16 che può portare a problemi di deserializzazione a valle. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Questo genera un'eccezione perché la dichiarazione afferma che è UTF-16 mentre il contenuto è stato effettivamente scritto come UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan

Per aggirare questo problema e continuare a usarlo XmlReader, puoi usare var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);The true userà la BOM se trovata, altrimenti l'impostazione predefinita che fornisci.
Tyler StandishMan

9

Suggerisco questa classe di aiuto:

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
}

:)


ottima risposta :) ho anche aggiunto questa linea stream.Position = 0; e ha restituito l'intero flusso nella mia soluzione .. ha funzionato come previsto - tutti i tag di decelerazione sono stati rimossi
ymz

L'aggiunta dell'argomento spazi dei nomi alla sola chiamata del serializzatore ha funzionato per me per rimuovere gli spazi dei nomi predefiniti. Scrivere new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})invece di new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})è un modo intenzionalmente più chiaro per codificarlo, secondo me.
Suncat2000

5

Se non sei in grado di sbarazzarti degli attributi xmlns aggiuntivi per ogni elemento, durante la serializzazione in xml dalle classi generate (ad esempio: quando è stato usato xsd.exe ), hai qualcosa come:

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

poi vorrei condividere con voi cosa ha funzionato per me (un mix di risposte precedenti e cosa ho trovato qui )

imposta esplicitamente tutti i tuoi diversi xmlns come segue:

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")

quindi passalo al serialize

serializer.Serialize(writer, object, xmlns);

avrai i tre spazi dei nomi dichiarati nell'elemento radice e non sarà più necessario generarli negli altri elementi che saranno prefissati di conseguenza

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...

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();
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.