Serialisieren Sie ein Objekt in XML

292

Ich habe eine C # -Klasse, die ich geerbt habe. Ich habe das Objekt erfolgreich "gebaut". Aber ich muss das Objekt in XML serialisieren. Gibt es eine einfache Möglichkeit, dies zu tun?

Es sieht so aus, als ob die Klasse für die Serialisierung eingerichtet wurde, aber ich bin nicht sicher, wie ich die XML-Darstellung erhalten soll. Meine Klassendefinition sieht folgendermaßen aus:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.domain.com/test")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.domain.com/test", IsNullable = false)]
public partial class MyObject
{
  ...
}

Ich dachte, ich könnte Folgendes tun, aber es funktioniert nicht:

MyObject o = new MyObject();
// Set o properties
string xml = o.ToString();

Wie erhalte ich die XML-Darstellung dieses Objekts?

user462166
quelle
1
Ich habe eine einfache Bibliothek entwickelt, um dies zu erreichen: github.com/aishwaryashiva/SaveXML
Aishwarya Shiva

Antworten:

510

Sie müssen XmlSerializer für die XML-Serialisierung verwenden. Unten finden Sie ein Beispiel-Snippet.

 XmlSerializer xsSubmit = new XmlSerializer(typeof(MyObject));
 var subReq = new MyObject();
 var xml = "";

 using(var sww = new StringWriter())
 {
     using(XmlWriter writer = XmlWriter.Create(sww))
     {
         xsSubmit.Serialize(writer, subReq);
         xml = sww.ToString(); // Your XML
     }
 }
RameshVel
quelle
10
Scheint ohne die Linie perfekt zu funktionierenXmlWriter writer = XmlWriter.Create(sww);
Paul Hunt
15
Um ein serialisiertes Objekt formatieren zu lassen, gehen Sie wie folgt vor: XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented };anstelle vonXmlWriter writer = XmlWriter.Create(sww);
Tono Nam
4
Da das XmlWritergekapselt ist, müssen StringWriterSie nicht beide entsorgen (die erste Verwendung ist redundant), oder? Ich gehe davon aus XmlWriterkümmert sich um dispose es ...
Talles
4
@talles XmlWriterkapselt das nicht ein StringWriter, es verwendet Ihr übergebenes StringWriterund hat keine Erwartung / Verantwortung, es zu entsorgen. Ferner StringWriterist außerhalb XmlWriterUmfang s‘, sie sie brauchen, wenn XmlWriterangeordnet ist, wäre es eine schlechte Verhalten für sein XmlWriterIhre entsorgen StringWriter. Wenn Sie etwas deklarieren, das entsorgt werden muss, sind Sie in der Regel dafür verantwortlich, es zu entsorgen. Und implizit zu dieser Regel, alles, was Sie nicht selbst deklarieren, sollten Sie nicht entsorgen. Also sind beide usings notwendig.
Arkaine55
3
using System.Xml.Serialization; using System.IO; using System.Xml;
Timothy
122

Ich habe meine geändert, um eine Zeichenfolge zurückzugeben, anstatt eine Ref-Variable wie unten zu verwenden.

public static string Serialize<T>(this T value)
{
    if (value == null)
    {
        return string.Empty;
    }
    try
    {
        var xmlserializer = new XmlSerializer(typeof(T));
        var stringWriter = new StringWriter();
        using (var writer = XmlWriter.Create(stringWriter))
        {
            xmlserializer.Serialize(writer, value);
            return stringWriter.ToString();
        }
    }
    catch (Exception ex)
    {
        throw new Exception("An error occurred", ex);
    }
}

Seine Verwendung wäre wie folgt:

var xmlString = obj.Serialize();
Kwex
quelle
8
Sehr schöne Lösung, ich mag die Art und Weise, wie Sie dies als Erweiterungsmethode implementiert haben
Spyros
57
Eine Sache, die ich hier vorschlagen würde: Entfernen Sie den try ... catch-Block. Es bringt Ihnen keinen Vorteil und verschleiert nur den Fehler, der ausgelöst wird.
Jammycakes
7
Müssen Sie nicht auch den Stringwriter verwenden? Beispiel: using (var stringWriter = new StringWriter ())
Steven Quick
3
@jammycakes Nein! Wenn Sie dort eine neue werfen Exception, haben Sie die StackTrace mit der Methode "Serialize <>" erweitert.
user11909
1
@ user2190035 sicher, wenn es innerhalb der Erweiterungsmethode brechen würde, würde der Stack-Trace dort beginnen? "Erweitern des Stack-Trace" mit dem Versuch erscheint unnötig?
LeRoi
43

Die folgende Funktion kann in jedes Objekt kopiert werden, um eine XML-Speicherfunktion mithilfe des System.Xml-Namespace hinzuzufügen.

/// <summary>
/// Saves to an xml file
/// </summary>
/// <param name="FileName">File path of the new xml file</param>
public void Save(string FileName)
{
    using (var writer = new System.IO.StreamWriter(FileName))
    {
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();
    }
}

Um das Objekt aus der gespeicherten Datei zu erstellen, fügen Sie die folgende Funktion hinzu und ersetzen Sie [ObjectType] durch den zu erstellenden Objekttyp.

/// <summary>
/// Load an object from an xml file
/// </summary>
/// <param name="FileName">Xml file name</param>
/// <returns>The object created from the xml file</returns>
public static [ObjectType] Load(string FileName)
{
    using (var stream = System.IO.File.OpenRead(FileName))
    {
        var serializer = new XmlSerializer(typeof([ObjectType]));
        return serializer.Deserialize(stream) as [ObjectType];
    }
}
Ben Gripka
quelle
writer.Flush()ist in einem usingBlock redundant - writerdie Dispose()Methode wird es für Sie spülen.
Bayaza
6
Meine Erfahrung hat gezeigt, dass das nicht stimmt. Bei größeren Daten wird der Stream durch die using-Anweisung entsorgt, bevor der Puffer gelöscht wird. Ich empfehle 100% explizit Flush aufzurufen.
Ben Gripka
6
writer.Flush () ist NICHT redundant, es MUSS da sein. Ohne Flush kann es vorkommen, dass sich ein Teil der Daten noch im StreamWriter-Puffer befindet und die Datei entsorgt wird und einige Daten fehlen.
Tomas Kubes
Ich mag Ihren Code sehr: kurz und ordentlich. Mein Problem ist, die Funktionen immer wieder in verschiedene Klassen zu kopieren: Ist es nicht eine Codeduplizierung? Die anderen Antworten schlagen eine generische Bibliothek mit Methoden zur Vorlagenerweiterung vor, die ich begrüßen würde. Was denken Sie?
Michael G
33

Erweiterungsklasse:

using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace MyProj.Extensions
{
    public static class XmlExtension
    {
        public static string Serialize<T>(this T value)
        {
            if (value == null) return string.Empty;

            var xmlSerializer = new XmlSerializer(typeof(T));

            using (var stringWriter = new StringWriter())
            {
                using (var xmlWriter = XmlWriter.Create(stringWriter,new XmlWriterSettings{Indent = true}))
                {
                    xmlSerializer.Serialize(xmlWriter, value);
                    return stringWriter.ToString();
                }    
            }
        }
    }
}

Verwendungszweck:

Foo foo = new Foo{MyProperty="I have been serialized"};

string xml = foo.Serialize();

Verweisen Sie einfach auf den Namespace, der Ihre Erweiterungsmethode enthält, in der Datei, in der Sie sie verwenden möchten, und es wird funktionieren (in meinem Beispiel wäre es: using MyProj.Extensions; )

Beachten Sie, dass Sie Foodas TArgument in der Erweiterungsmethode ersetzen können , wenn Sie die Erweiterungsmethode nur für eine bestimmte Klasse (z. B. ) spezifisch machen möchten .

public static string Serialize(this Foo value){...}

Aleksandr Albert
quelle
31

Sie können die folgende Funktion verwenden, um serialisiertes XML von jedem Objekt abzurufen.

public static bool Serialize<T>(T value, ref string serializeXml)
{
    if (value == null)
    {
        return false;
    }
    try
    {
        XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
        StringWriter stringWriter = new StringWriter();
        XmlWriter writer = XmlWriter.Create(stringWriter);

        xmlserializer.Serialize(writer, value);

        serializeXml = stringWriter.ToString();

        writer.Close();
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

Sie können dies vom Client aus aufrufen.

Imrul
quelle
21

Gehen Sie wie folgt vor, um ein Objekt zu serialisieren:

 using (StreamWriter myWriter = new StreamWriter(path, false))
 {
     XmlSerializer mySerializer = new XmlSerializer(typeof(your_object_type));
     mySerializer.Serialize(myWriter, objectToSerialize);
 }

Denken Sie auch daran, dass Sie einen parameterlosen Konstruktor benötigen, damit XmlSerializer funktioniert.

Rox
quelle
2
Das hat mich verrückt gemacht. Ich konnte nicht herausfinden, warum es immer leer war. Dann wurde mir klar, dass ich nach dem Lesen Ihrer Antwort keinen Konstruktor ohne Parameter hatte. Danke dir.
Andy
19

Ich werde mit der Antwort von Ben Gripka beginnen:

public void Save(string FileName)
{
    using (var writer = new System.IO.StreamWriter(FileName))
    {
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();
    }
}

Ich habe diesen Code früher verwendet. Die Realität hat jedoch gezeigt, dass diese Lösung etwas problematisch ist. Normalerweise serialisieren die meisten Programmierer die Einstellungen beim Speichern nur und deserialisieren die Einstellungen beim Laden. Dies ist ein optimistisches Szenario. Sobald die Serialisierung fehlgeschlagen ist, wird die Datei aus irgendeinem Grund teilweise geschrieben, die XML-Datei ist nicht vollständig und ungültig. Infolgedessen funktioniert die XML-Deserialisierung nicht und Ihre Anwendung kann beim Start abstürzen. Wenn die Datei nicht riesig ist, schlage ich vor, zuerst das Objekt zu serialisierenMemoryStream dann den Stream in die Datei schreiben. Dieser Fall ist besonders wichtig, wenn eine komplizierte benutzerdefinierte Serialisierung vorliegt. Sie können niemals alle Fälle testen.

public void Save(string fileName)
{
    //first serialize the object to memory stream,
    //in case of exception, the original file is not corrupted
    using (MemoryStream ms = new MemoryStream())
    {
        var writer = new System.IO.StreamWriter(ms);    
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();

        //if the serialization succeed, rewrite the file.
        File.WriteAllBytes(fileName, ms.ToArray());
    }
}

Die Deserialisierung im realen Szenario sollte mit einer beschädigten Serialisierungsdatei zählen, es kommt irgendwann vor. Die Ladefunktion von Ben Gripka ist in Ordnung.

public static [ObjectType] Load(string fileName)
{
    using (var stream = System.IO.File.OpenRead(fileName))
    {
        var serializer = new XmlSerializer(typeof([ObjectType]));
        return serializer.Deserialize(stream) as [ObjectType];        
    }    
}

Und es könnte durch ein Wiederherstellungsszenario verpackt werden. Es eignet sich für Einstellungsdateien oder andere Dateien, die bei Problemen gelöscht werden können.

public static [ObjectType] LoadWithRecovery(string fileName)
{
    try
    {
        return Load(fileName);
    }
    catch(Excetion)
    {
        File.Delete(fileName); //delete corrupted settings file
        return GetFactorySettings();
    }
}
Tomas Kubes
quelle
Kann der Prozess nicht unterbrochen werden, während der MemoryStream in eine Datei geschrieben wird, z. B. durch Herunterfahren?
John Smith
1
Ja, es ist möglich. Sie können dies vermeiden, indem Sie Einstellungen in eine temporäre Datei schreiben und dann das Original ersetzen.
Tomas Kubes
18

Alle oben genannten Antworten sind korrekt. Dies ist nur die einfachste Version:

private string Serialize(Object o)
{
    using (var writer = new StringWriter())
    {
        new XmlSerializer(o.GetType()).Serialize(writer, o);
        return writer.ToString();
    }
}
avj
quelle
9

Es ist ein bisschen komplizierter als das Anrufen ToString Methode der Klasse, aber nicht viel.

Hier ist eine einfache Drop-In-Funktion, mit der Sie jeden Objekttyp serialisieren können. Es wird eine Zeichenfolge zurückgegeben, die den serialisierten XML-Inhalt enthält:

public string SerializeObject(object obj)
{
    System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
    using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) {
        serializer.Serialize(ms, obj);
        ms.Position = 0;
        xmlDoc.Load(ms);
        return xmlDoc.InnerXml;
    }
}
Cody Grey
quelle
4
    string FilePath = ConfigurationReader.FileLocation;   //Getting path value from web.config            
    XmlSerializer serializer = new XmlSerializer(typeof(Devices)); //typeof(object)
            MemoryStream memStream = new MemoryStream();
            serializer.Serialize(memStream, lstDevices);//lstdevices : I take result as a list.
            FileStream file = new FileStream(folderName + "\\Data.xml", FileMode.Create, FileAccess.ReadWrite); //foldername:Specify the path to store the xml file
            memStream.WriteTo(file);
            file.Close();

Sie können das Ergebnis als XML-Datei am gewünschten Speicherort erstellen und speichern.

Dev Try
quelle
4

mein Arbeitscode. Gibt den leeren Namespace utf8 xml enable zurück.

// override StringWriter
public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => Encoding.UTF8;
}

private string GenerateXmlResponse(Object obj)
{    
    Type t = obj.GetType();

    var xml = "";

    using (StringWriter sww = new Utf8StringWriter())
    {
        using (XmlWriter writer = XmlWriter.Create(sww))
        {
            var ns = new XmlSerializerNamespaces();
            // add empty namespace
            ns.Add("", "");
            XmlSerializer xsSubmit = new XmlSerializer(t);
            xsSubmit.Serialize(writer, obj, ns);
            xml = sww.ToString(); // Your XML
        }
    }
    return xml;
}

Beispiel gibt Antwort zurück Yandex api Zahlung Aviso URL:

<?xml version="1.0" encoding="utf-8"?><paymentAvisoResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" performedDatetime="2017-09-01T16:22:08.9747654+07:00" code="0" shopId="54321" invoiceId="12345" orderSumAmount="10643" />
Dev-Sibirien
quelle
4

Ich habe eine einfache Möglichkeit, ein Objekt mit C # in XML zu serialisieren. Es funktioniert hervorragend und ist in hohem Maße wiederverwendbar. Ich weiß, dass dies ein älterer Thread ist, aber ich wollte dies posten, weil jemand dies für ihn hilfreich finden könnte.

So nenne ich die Methode:

var objectToSerialize = new MyObject();
var xmlString = objectToSerialize.ToXmlString();

Hier ist die Klasse, die die Arbeit macht:

Hinweis: Da es sich um Erweiterungsmethoden handelt, müssen sie sich in einer statischen Klasse befinden.

using System.IO;
using System.Xml.Serialization;

public static class XmlTools
{
    public static string ToXmlString<T>(this T input)
    {
        using (var writer = new StringWriter())
        {
            input.ToXml(writer);
            return writer.ToString();
        }
    }

    private static void ToXml<T>(this T objectToSerialize, StringWriter writer)
    {
        new XmlSerializer(typeof(T)).Serialize(writer, objectToSerialize);
    }
}
Tyler Kalosza
quelle
4

Basierend auf den oben genannten Lösungen finden Sie hier eine Erweiterungsklasse, mit der Sie jedes Objekt serialisieren und deserialisieren können. Alle anderen XML-Zuordnungen liegen bei Ihnen.

Verwenden Sie es einfach so:

        string s = new MyObject().Serialize(); // to serialize into a string
        MyObject b = s.Deserialize<MyObject>();// deserialize from a string



internal static class Extensions
{
    public static T Deserialize<T>(this string value)
    {
        var xmlSerializer = new XmlSerializer(typeof(T));

        return (T)xmlSerializer.Deserialize(new StringReader(value));
    }

    public static string Serialize<T>(this T value)
    {
        if (value == null)
            return string.Empty;

        var xmlSerializer = new XmlSerializer(typeof(T));

        using (var stringWriter = new StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true }))
            {
                xmlSerializer.Serialize(xmlWriter, value);
                return stringWriter.ToString();
            }
        }
    }
}
Hefaistos68
quelle
2

Oder Sie können diese Methode zu Ihrem Objekt hinzufügen:

    public void Save(string filename)
    {
        var ser = new XmlSerializer(this.GetType());
        using (var stream = new FileStream(filename, FileMode.Create))
            ser.Serialize(stream, this);
    }
Bigjim
quelle
1

Hier ist ein grundlegender Code, der beim Serialisieren der C # -Objekte in XML hilft:

using System;

public class clsPerson
{
  public  string FirstName;
  public  string MI;
  public  string LastName;
}

class class1
{ 
   static void Main(string[] args)
   {
      clsPerson p=new clsPerson();
      p.FirstName = "Jeff";
      p.MI = "A";
      p.LastName = "Price";
      System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
      x.Serialize(Console.Out, p);
      Console.WriteLine();
      Console.ReadLine();
   }
}    
Ali Asad
quelle
6
Es wäre schön, wenn Sie die Quelle dieses Codes zitieren: support.microsoft.com/en-us/help/815813/…
MaLiN2223
0
public string ObjectToXML(object input)
{
    try
    {
        var stringwriter = new System.IO.StringWriter();
        var serializer = new XmlSerializer(input.GetType());
        serializer.Serialize(stringwriter, input);
        return stringwriter.ToString();
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null)
            ex = ex.InnerException;

        return "Could not convert: " + ex.Message;
    }
}

//Usage
var res = ObjectToXML(obj)

Sie müssen folgende Klassen verwenden:

using System.IO;
using System.Xml;
using System.Xml.Serialization;
Sagar Timalsina
quelle