Membuat serial objek ke XML

292

Saya memiliki kelas C # yang saya warisi. Saya telah berhasil "membangun" objek. Tapi saya perlu membuat serialisasi objek ke XML. Apakah ada cara mudah untuk melakukannya?

Sepertinya kelas telah diatur untuk serialisasi, tapi saya tidak yakin bagaimana mendapatkan representasi XML. Definisi kelas saya terlihat seperti ini:

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

Inilah yang saya pikir bisa saya lakukan, tetapi tidak berhasil:

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

Bagaimana saya mendapatkan representasi XML dari objek ini?

pengguna462166
sumber
Silakan lihat juga: Serialisasi dan Deserialisasi XML pada CodeProject
Behzad Ebrahimi
1
Saya mengembangkan perpustakaan sederhana untuk mencapai hal ini: github.com/aishwaryashiva/SaveXML
Aishwarya Shiva

Jawaban:

510

Anda harus menggunakan XmlSerializer untuk serialisasi XML. Di bawah ini adalah cuplikan sampel.

 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
sumber
10
Tampaknya bekerja dengan baik tanpa garisXmlWriter writer = XmlWriter.Create(sww);
Paul Hunt
15
Untuk memiliki objek serial yang diformat, lakukan: XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented };alih-alihXmlWriter writer = XmlWriter.Create(sww);
Tono Nam
4
Karena XmlWritermengenkapsulasi StringWriterAnda tidak perlu membuang keduanya (penggunaan pertama adalah redundan), bukan? Saya berasumsi XmlWriterberhati-hati membuangnya ...
tinggi
4
@talles XmlWritertidak merangkum StringWriter, itu memanfaatkan pass-in Anda StringWriterdan tidak memiliki harapan / tanggung jawab untuk membuangnya. Selanjutnya StringWriteradalah di luar XmlWriterruang lingkup, Anda mungkin masih menginginkannya ketika XmlWriterdibuang, itu akan menjadi perilaku yang buruk untuk XmlWritermembuang StringWriter. Sebagai aturan umum, jika Anda menyatakan sesuatu yang perlu dibuang Anda bertanggung jawab untuk membuangnya. Dan tersirat pada aturan itu, apa pun yang tidak Anda nyatakan sendiri tidak boleh Anda buang. Jadi keduanya usingdiperlukan.
Arkaine55
3
menggunakan System.Xml.Serialisasi; menggunakan System.IO; menggunakan System.Xml;
timothy
122

Saya memodifikasi tambang untuk mengembalikan string daripada menggunakan variabel ref seperti di bawah ini.

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

Penggunaannya akan seperti ini:

var xmlString = obj.Serialize();
Kwex
sumber
8
solusi yang sangat bagus, saya suka cara Anda menerapkan ini sebagai metode ekstensi
Spyros
57
Satu hal yang saya sarankan di sini: hapus try ... catch block. Itu tidak memberi Anda manfaat apa pun dan hanya mengaburkan kesalahan yang dilemparkan.
jammycakes
7
Apakah Anda juga tidak perlu menggunakan pada penulis naskah? misal: using (var stringWriter = new StringWriter ())
Steven Quick
3
@jammycakes Tidak! Ketika Anda melempar yang baru ke Exceptionsana, Anda telah memperpanjang StackTrace dengan metode "Serialize <>".
user11909
1
@ user2190035 tentu saja jika ingin menerobos dalam metode ekstensi jejak tumpukan akan mulai di sana? "Memperluas jejak tumpukan" dengan mencoba sepertinya tidak perlu?
LeRoi
43

Fungsi berikut ini dapat disalin ke objek apa pun untuk menambahkan fungsi penyimpanan XML menggunakan namespace 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();
    }
}

Untuk membuat objek dari file yang disimpan, tambahkan fungsi berikut dan ganti [ObjectType] dengan tipe objek yang akan dibuat.

/// <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
sumber
writer.Flush()adalah berlebihan dalam usingblok - writer's Dispose()metode akan menyiram untuk Anda.
bavaza
6
Pengalaman saya menemukan itu tidak benar. Dengan data yang lebih besar, pernyataan penggunaan akan membuang aliran sebelum buffer dihapus. Saya 100% merekomendasikan secara eksplisit memanggil flush.
Ben Gripka
6
writer.Flush () TIDAK berlebihan, itu HARUS ada di sana. Tanpa Flush, dapat terjadi bahwa sebagian data masih dalam buffer StreamWriter dan file dibuang dan beberapa data hilang.
Tomas Kubes
Saya sangat suka kode Anda: pendek dan rapi. Masalah saya adalah dengan menyalin fungsi berulang-ulang ke kelas yang berbeda: bukankah itu duplikasi kode? Jawaban lain menyarankan perpustakaan umum dengan metode ekstensi templat, yang akan saya terima. Bagaimana menurut anda?
Michael G
33

Kelas ekstensi:

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

Pemakaian:

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

string xml = foo.Serialize();

Hanya referensi namespace memegang metode ekstensi Anda dalam file yang Anda ingin menggunakannya dalam dan itu akan bekerja (dalam contoh saya akan: using MyProj.Extensions;)

Perhatikan bahwa jika Anda ingin membuat metode ekstensi hanya untuk kelas tertentu (mis., Foo), Anda bisa mengganti Targumen dalam metode ekstensi, mis.

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

Aleksandr Albert
sumber
31

Anda dapat menggunakan fungsi seperti di bawah ini untuk mendapatkan XML serial dari objek apa pun.

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

Anda dapat memanggil ini dari klien.

Imrul
sumber
21

Untuk membuat serial objek, lakukan:

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

Juga ingat bahwa agar XmlSerializer berfungsi, Anda memerlukan konstruktor tanpa parameter.

Rox
sumber
2
Ini membuatku gila. Saya tidak tahu mengapa itu selalu kosong. Kemudian menyadari bahwa saya tidak memiliki konstruktor tanpa parameter setelah membaca jawaban Anda. Terima kasih.
Andy
19

Saya akan mulai dengan jawaban salinan dari 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();
    }
}

Saya menggunakan kode ini sebelumnya. Tetapi kenyataan menunjukkan bahwa solusi ini agak bermasalah. Biasanya sebagian besar programmer hanya membuat pengaturan serial pada save dan deserialize pada load. Ini adalah skenario optimis. Setelah serialisasi gagal, karena beberapa alasan, file sebagian ditulis, file XML tidak lengkap dan tidak valid. Karena itu deserialisasi XML tidak berfungsi dan aplikasi Anda mungkin macet saat mulai. Jika file tidak besar, saya sarankan objek bersambung terlebih dahulu untuk MemoryStreamkemudian menulis aliran ke File. Kasus ini sangat penting jika ada beberapa serialisasi kustom yang rumit. Anda tidak akan pernah bisa menguji semua kasus.

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

Deserialisasi dalam skenario dunia nyata harus dihitung dengan file serialisasi yang rusak, itu terjadi kapan-kapan. Fungsi pemuatan yang disediakan oleh Ben Gripka baik-baik saja.

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

Dan itu bisa dibungkus dengan beberapa skenario pemulihan. Sangat cocok untuk file pengaturan atau file lain yang dapat dihapus jika ada masalah.

public static [ObjectType] LoadWithRecovery(string fileName)
{
    try
    {
        return Load(fileName);
    }
    catch(Excetion)
    {
        File.Delete(fileName); //delete corrupted settings file
        return GetFactorySettings();
    }
}
Tomas Kubes
sumber
Apakah tidak mungkin proses terputus saat menulis MemoryStream ke file, misalnya dengan pematian daya?
John Smith
1
Ya itu mungkin. Anda dapat menghindarinya dengan menulis pengaturan ke file sementara dan kemudian mengganti yang asli.
Tomas Kubes
18

Semua jawaban yang dipilih di atas benar. Ini hanya versi paling sederhana:

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

Ini sedikit lebih rumit daripada memanggil ToStringmetode kelas, tetapi tidak banyak.

Berikut adalah fungsi drop-in sederhana yang dapat Anda gunakan untuk membuat serial semua jenis objek. Ini mengembalikan string yang berisi konten XML serial:

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

Anda dapat membuat dan menyimpan hasilnya sebagai file xml di lokasi yang diinginkan.

Dev Coba
sumber
4

kode kerja saya. Mengembalikan utf8 xml mengaktifkan namespace kosong.

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

Contoh pengembalian respons pembayaran Yandex api 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-siberia
sumber
4

Saya punya cara sederhana untuk membuat serialisasi objek ke XML menggunakan C #, ini berfungsi dengan baik dan sangat bisa digunakan kembali. Saya tahu ini adalah utas yang lebih lama, tetapi saya ingin memposting ini karena seseorang mungkin menganggap ini bermanfaat bagi mereka.

Inilah cara saya memanggil metode:

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

Inilah kelas yang berfungsi:

Catatan: Karena ini adalah metode ekstensi, mereka harus berada dalam kelas statis.

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
sumber
4

Berdasarkan solusi di atas, inilah kelas ekstensi yang dapat Anda gunakan untuk membuat serial dan deserialisasi objek apa pun. Atribusi XML lainnya terserah Anda.

Gunakan saja seperti ini:

        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
sumber
2

Atau Anda dapat menambahkan metode ini ke objek Anda:

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

Berikut adalah kode dasar yang akan membantu membuat serial objek C # ke dalam 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();
   }
}    
Ali Asad
sumber
6
Akan lebih baik jika Anda mengutip sumber kode ini: 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)

Anda perlu menggunakan kelas-kelas berikut:

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