Comment sérialiser un objet en XML sans obtenir xmlns = «…»?

109

Existe-t-il un moyen pour moi de sérialiser un objet dans .NET sans que les espaces de noms XML ne sérialisent également automatiquement? Il semble que par défaut .NET pense que les espaces de noms XSI et XSD devraient être inclus, mais je ne les veux pas.

Wes P
la source

Réponses:

142

Ahh ... tant pis. C'est toujours la recherche après que la question est posée qui donne la réponse. Mon objet qui est sérialisé est objet a déjà été défini. L'ajout d'un XMLSerializerNamespace avec un seul espace de noms vide à la collection fait l'affaire.

Dans VB comme ceci:

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

en C # comme ceci:

//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
la source
12
J'ai essayé cela dans VB, les attributs xsi et xsd ont disparu mais des attributs tels que xmlns: q12 =, d3p1: type et xmlns: d3p1 sont apparus.
MiddleKay
16
J'ai essayé la version C # et elle a supprimé les xsi et xsd mais a ajouté un préfixe de q1: à tous les noms de balises XML, ce que je ne voulais pas. Il semble que l'exemple C # soit incomplet, référençant myXmlTextWriter qui, je suppose, doit être initialisé de la même manière que l'exemple VB.
redtetrahedron
1
@redtetrahedron Avez-vous trouvé un moyen de vous débarrasser de la q1merde?
écraser le
Reportez-vous à la réponse stackoverflow.com/questions/31946240/… , si q1 est ajouté en tant
qu'espace de
20

Si vous voulez vous débarrasser du supplément xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"et xmlns:xsd="http://www.w3.org/2001/XMLSchema", tout en conservant votre propre espace de noms xmlns="http://schemas.YourCompany.com/YourSchema/", vous utilisez le même code que ci-dessus, sauf pour ce simple changement:

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

Si vous souhaitez supprimer l'espace de noms, vous pouvez également supprimer la version, pour vous éviter de rechercher, j'ai ajouté cette fonctionnalité afin que le code ci-dessous fasse les deux.

Je l'ai également enveloppé dans une méthode générique car je crée de très gros fichiers xml qui sont trop volumineux pour être sérialisés en mémoire, j'ai donc décomposé mon fichier de sortie et le sérialiser en plus petits «morceaux»:

    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
        }
    }
D34e
la source
Attention, le StringWritercodage UTF-16 par défaut peut entraîner des problèmes de désérialisation en aval. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Cela lève une exception car la déclaration indique qu'il s'agit de UTF-16 alors que le contenu était en fait écrit en UTF-8. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan le
Pour contourner ce problème et continuer à l'utiliser XmlReader, vous pouvez utiliser var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);La valeur true utilisera la nomenclature si elle est trouvée, sinon la valeur par défaut que vous fournissez.
Tyler StandishMan le
9

Je suggère cette classe d'assistance:

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
la source
excellente réponse :) j'ai également ajouté cette ligne stream.Position = 0; et renvoyé l'intégralité du flux dans ma solution .. a fonctionné comme prévu - toutes les balises de décélération ont été supprimées
ymz
L'ajout de l'argument des espaces de noms à l'appel du sérialiseur seul a fonctionné pour moi pour supprimer les espaces de noms par défaut. À mon avis, écrire new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})au lieu de new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})est un moyen intentionnellement plus clair de le coder.
Suncat2000
5

Si vous ne parvenez pas à vous débarrasser des attributs xmlns supplémentaires pour chaque élément, lors de la sérialisation vers xml à partir des classes générées (par exemple: lorsque xsd.exe a été utilisé), vous avez donc quelque chose comme:

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

puis je partagerais avec vous ce qui a fonctionné pour moi (un mélange de réponses précédentes et ce que j'ai trouvé ici )

définissez explicitement tous vos différents xmlns comme suit:

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

puis passez-le à la sérialisation

serializer.Serialize(writer, object, xmlns);

vous aurez les trois espaces de noms déclarés dans l'élément racine et il ne sera plus nécessaire de les générer dans les autres éléments qui seront préfixés en conséquence

<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
   <one:Element />
   <two:ElementFromAnotherNameSpace /> ...
vinjenzo
la source
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();
        }
Taureau999able
la source