Wie serialisiere ich ein Objekt in XML, ohne xmlns = "..." zu erhalten?

109

Gibt es eine Möglichkeit für mich, ein Objekt in .NET zu serialisieren, ohne dass die XML-Namespaces auch automatisch serialisiert werden? Es scheint, dass .NET standardmäßig der Meinung ist, dass die XSI- und XSD-Namespaces enthalten sein sollten, aber ich möchte sie dort nicht.

Wes P.
quelle

Antworten:

142

Ahh ... egal. Es ist immer die Suche nach der Frage, die die Antwort liefert. Mein Objekt, das serialisiert wird, istobj und wurde bereits definiert. Das Hinzufügen eines XMLSerializerNamespace mit einem einzelnen leeren Namespace zur Sammlung reicht aus.

In VB so:

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 # so:

//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.
quelle
12
Ich habe dies in VB versucht. Die Attribute xsi und xsd verschwanden, aber Attribute wie xmlns: q12 =, d3p1: type und xmlns: d3p1 wurden angezeigt.
MiddleKay
16
Ich habe die C # -Version ausprobiert und xsi und xsd entfernt, aber allen XML-Tag-Namen, die ich nicht wollte, das Präfix q1: hinzugefügt. Es sieht so aus, als ob das C # -Beispiel unvollständig ist und auf myXmlTextWriter verweist, von dem ich annehme, dass es auf die gleiche Weise wie das VB-Beispiel initialisiert werden muss.
Redtetrahedron
1
@redtetrahedron Hast du einen Weg gefunden, den q1Mist loszuwerden ?
Crush
Lesen Sie die Antwort stackoverflow.com/questions/31946240/… , wenn q1 als leerer Namespace hinzugefügt wurde
aniruddha
20

Wenn Sie das zusätzliche xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"und xmlns:xsd="http://www.w3.org/2001/XMLSchema"dennoch Ihren eigenen Namespace entfernen möchten xmlns="http://schemas.YourCompany.com/YourSchema/", verwenden Sie bis auf diese einfache Änderung denselben Code wie oben:

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

Wenn Sie den Namespace entfernen möchten, möchten Sie möglicherweise auch die Version entfernen. Um Ihnen die Suche zu ersparen, habe ich diese Funktionalität hinzugefügt, damit der folgende Code beides kann.

Ich habe es auch in eine generische Methode eingeschlossen, da ich sehr große XML-Dateien erstelle, die zu groß sind, um im Speicher zu serialisieren. Daher habe ich meine Ausgabedatei aufgeschlüsselt und in kleinere "Blöcke" serialisiert:

    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
        }
    }
D34
quelle
Beachten Sie, dass StringWriterstandardmäßig die UTF-16-Codierung verwendet wird, die zu nachgeschalteten Deserialisierungsproblemen führen kann. using (var reader = XmlReader.Create(stream)){ reader.Read(); }Dies löst eine Ausnahme aus, da in der Deklaration angegeben ist, dass es sich um UTF-16 handelt, während der Inhalt tatsächlich als UTF-8 geschrieben wurde. System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
Tyler StandishMan
Um dies zu umgehen und weiterhin zu verwenden XmlReader, können Sie verwenden. var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true);The true verwendet die Stückliste, falls gefunden, andernfalls die von Ihnen angegebene Standardeinstellung.
Tyler StandishMan
9

Ich schlage diese Hilfsklasse vor:

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
quelle
tolle Antwort :) Ich habe auch diesen Zeilenstrom hinzugefügt.Position = 0; und gab den gesamten Stream in meiner Lösung zurück .. funktionierte wie erwartet - alle Verzögerungs-Tags wurden entfernt
ymz
Das Hinzufügen des Namespaces-Arguments zum Serializer-Aufruf allein hat mir geholfen, die Standard-Namespaces zu entfernen. Schreiben new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty})statt new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")})ist meiner Meinung nach eine absichtlich klarere Möglichkeit, es zu codieren.
Suncat2000
5

Wenn Sie nicht in der Lage sind, zusätzliche xmlns-Attribute für jedes Element zu entfernen , wenn Sie aus generierten Klassen in xml serialisieren (z. B. wenn xsd.exe verwendet wurde), haben Sie Folgendes :

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

dann würde ich mit Ihnen teilen, was für mich funktioniert hat (eine Mischung aus früheren Antworten und dem, was ich hier gefunden habe )

Stellen Sie alle Ihre verschiedenen XML-Dateien explizit wie folgt ein:

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

Übergeben Sie es dann an die Serialisierung

serializer.Serialize(writer, object, xmlns);

Sie haben die drei Namespaces im Stammelement deklariert und müssen nicht mehr in den anderen Elementen generiert werden, denen ein entsprechendes Präfix vorangestellt wird

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