Serializarea unui obiect în XML (Programare, C#, Serializare Xml)

user462166 a intrebat.

Am o clasă C# pe care am moștenit-o. Am reușit să „construiesc” obiectul cu succes. Dar am nevoie să serializez obiectul în XML. Există o modalitate ușoară de a face acest lucru?

Se pare că clasa a fost configurată pentru serializare, dar nu sunt sigur cum să obțin reprezentarea XML. Definiția clasei mele arată astfel:

[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
{
  ...
}

Iată ce am crezut că pot face, dar nu funcționează:

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

Cum pot obține reprezentarea XML a acestui obiect?

Comentarii

17 răspunsuri
RameshVel

Trebuie să utilizați XmlSerializer pentru serializarea XML. Mai jos este un fragment de probă.

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

Comentarii

  • Pare să funcționeze perfect bine fără linia XmlWriter writer = XmlWriter.Create(sww); –  > Por Paul Hunt.
  • 15

  • Pentru a formata un obiect serializat, faceți: XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented }; în loc de XmlWriter writer = XmlWriter.Create(sww); –  > Por Tono Nam.
  • De la XmlWriter încapsulează StringWriter nu este nevoie să le eliminați pe amândouă (prima utilizare este redundantă), nu-i așa? Presupun că XmlWriter se ocupă de eliminarea ei… –  > Por talles.
  • @talles XmlWriter nu este încapsularea StringWriterci utilizează aplicația dvs. transmisă StringWriterși nu are nicio așteptare/responsabilitate de a-l elimina. Mai departe StringWriter este în afara XmlWriterdar este posibil să o doriți în continuare atunci când XmlWriter este eliminat, ar fi un comportament inadecvat pentru XmlWriter să elimine StringWriter. Ca regulă generală, dacă declarați ceva care trebuie eliminat, sunteți responsabil pentru eliminarea acestuia. Și implicit la această regulă, orice lucru pe care nu îl declarați dvs. nu ar trebui eliminat. Așadar, atât usingsunt necesare. –  > Por Arkaine55.
  • using System.Xml.Serialization; using System.IO; using System.Xml; –  > Por timothy.
Kwex

L-am modificat pe al meu pentru a returna un șir de caractere în loc să folosesc o variabilă ref ca mai jos.

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

Utilizarea sa ar fi ca aceasta:

var xmlString = obj.Serialize();

Comentarii

  • foarte bună soluție, îmi place modul în care ați implementat această metodă ca o metodă de extensie –  > Por Spyros.
  • 64

  • Un lucru pe care l-aș sugera aici: eliminați blocul try…catch. Nu vă oferă niciun beneficiu și nu face decât să ascundă eroarea care este aruncată. –  > Por jammycakes.
  • Nu ai nevoie și de using pe stringwriter? ex: using(var stringWriter = new StringWriter()) – –  > Por Steven Quick.
  • @jammycakes Nu! Când aruncați un nou Exception acolo, ați extins StackTrace cu metoda „Serialize<>”. –  > Por user11909.
  • @user2190035 cu siguranță dacă ar fi să se întrerupă în cadrul metodei de extensie, stack trace-ul ar începe acolo? „Extinderea urmăririi stivei” cu „try” pare inutilă? –  > Por LeRoi.
Ben Gripka

Următoarea funcție poate fi copiată în orice obiect pentru a adăuga o funcție de salvare XML folosind spațiul de nume System.Xml.

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

Pentru a crea obiectul din fișierul salvat, adăugați următoarea funcție și înlocuiți [ObjectType] cu tipul de obiect care urmează să fie creat.

/// <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];
    }
}

Comentarii

  • writer.Flush() este redundantă în cadrul unui using bloc – writer‘s Dispose() o va șterge în locul dumneavoastră. –  > Por bavaza.
  • Experiența mea a constatat că nu este adevărat. Cu date mai mari, instrucțiunea using va elimina fluxul înainte ca bufferul să fie golit. Vă recomand 100% să apelați explicit flush. –  > Por Ben Gripka.
  • writer.Flush() NU este redundant, ci TREBUIE să fie acolo. Fără Flush, se poate întâmpla ca o parte din date să fie încă în bufferul StreamWriter și fișierul să fie eliminat, iar unele date să lipsească. –  > Por Tomas Kubes.
  • Îmi place foarte mult codul tău: scurt și îngrijit. Problema mea este legată de copierea funcțiilor din nou și din nou în diferite clase: nu este o dublare a codului? Celelalte răspunsuri sugerează o bibliotecă generică cu metode de extensie a șabloanelor, pe care eu le-aș accepta. Ce părere aveți? –  > Por Michael G.
Aleksandr Albert

Clasa de extensie:

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();
                }    
            }
        }
    }
}

Utilizare:

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

string xml = foo.Serialize();

Trebuie doar să faceți referire la spațiul de nume care deține metoda de extensie în fișierul în care doriți să o utilizați și va funcționa (în exemplul meu ar fi: using MyProj.Extensions;)

Rețineți că, dacă doriți ca metoda de extensie să fie specifică doar pentru o anumită clasă (de exemplu., Foo), puteți să înlocuiți T în metoda de extensie, de exemplu

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

Imrul

Puteți utiliza funcția ca mai jos pentru a obține XML serializat din orice obiect.

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

Puteți apela această funcție din client.

Rox

Pentru a serializa un obiect, faceți:

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

Rețineți, de asemenea, că pentru ca XmlSerializer să funcționeze, aveți nevoie de un constructor fără parametri.

Comentarii

  • Acest lucru mă înnebunea. Nu-mi puteam da seama de ce era mereu gol. Apoi mi-am dat seama că nu aveam un constructor fără parametri după ce am citit răspunsul tău. Vă mulțumesc. –  > Por Andy.
avj

Toate răspunsurile upvoted de mai sus sunt corecte. Aceasta este doar cea mai simplă versiune:

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

Tomas Kubes

Voi începe cu răspunsul copiat de Ben Gripka:

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();
    }
}

Am folosit acest cod mai devreme. Dar realitatea a arătat că această soluție este un pic problematică. De obicei, majoritatea programatorilor se limitează la serializarea setărilor la salvare și la deserializarea setărilor la încărcare. Acesta este un scenariu optimist. Odată ce serializarea a eșuat, din anumite motive, fișierul este scris parțial, fișierul XML nu este complet și este invalid. În consecință, deserializarea XML nu funcționează, iar aplicația dumneavoastră se poate bloca la pornire. În cazul în care fișierul nu este uriaș, vă sugerez să serializați mai întâi obiectul la MemoryStream apoi să scrie fluxul în fișier. Acest caz este deosebit de important în cazul în care există o serializare personalizată complicată. Nu puteți testa niciodată toate cazurile.

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());
    }
}

Deserializarea în scenariul din lumea reală ar trebui să conteze cu un fișier de serializare corupt, se întâmplă uneori. Funcția de încărcare furnizată de Ben Gripka este bună.

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

Și ar putea fi înfășurată de un anumit scenariu de recuperare. Este potrivit pentru fișierele de setări sau alte fișiere care pot fi șterse în caz de probleme.

public static [ObjectType] LoadWithRecovery(string fileName)
{
    try
    {
        return Load(fileName);
    }
    catch(Excetion)
    {
        File.Delete(fileName); //delete corrupted settings file
        return GetFactorySettings();
    }
}

Comentarii

  • Nu este posibil ca procesul să fie întrerupt în timpul scrierii MemoryStream într-un fișier, de exemplu, de o oprire a alimentării? –  > Por John Smith.
  • Da, este posibil. Puteți evita acest lucru prin scrierea setărilor într-un fișier temporar și apoi înlocuirea originalului. –  > Por Tomas Kubes.
Cody Gray

Este un pic mai complicat decât să apelezi la funcția ToString a clasei, dar nu foarte mult.

Iată o funcție simplă de tip drop-in pe care o puteți folosi pentru a serializa orice tip de obiect. Aceasta returnează un șir de caractere care conține conținutul XML serializat:

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

Aamir

Iată un tutorial bun despre cum se face acest lucru

În principiu, ar trebui să utilizați System.Xml.Serialization.XmlSerializer clasa pentru a face acest lucru.

Tyler Kalosza

Am o modalitate simplă de a serializa un obiect în XML folosind C#, funcționează foarte bine și este foarte reutilizabil. Știu că acesta este un fir mai vechi, dar am vrut să postez acest lucru pentru că cineva ar putea găsi acest lucru util pentru ei.

Iată cum apelez metoda:

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

Aici este clasa care face munca:

Notă: Deoarece acestea sunt metode de extensie, ele trebuie să fie într-o clasă statică.

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

Hefaistos68

Pe baza soluțiilor de mai sus, iată că vine o clasă de extensie pe care o puteți folosi pentru a serializa și deserializa orice obiect. Orice alte atribuții XML sunt la latitudinea dumneavoastră.

Folosiți-o doar așa:

        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();
            }
        }
    }
}

Dev Try
    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();

Puteți crea și stoca rezultatul ca fișier xml în locația dorită.

dev-siberia

codul meu de lucru. Returnează utf8 xml permite spațiu de nume gol.

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

Exemplul returnează răspunsul Yandex api plată 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" />

Bigjim

Sau puteți adăuga această metodă la obiectul dumneavoastră:

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

Ali Asad

Iată un cod de bază care va ajuta la serializarea obiectelor C# în xml:

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();
   }
}    

Comentarii

Sagar Timalsina
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)

Trebuie să folosiți următoarele clase:

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