Bir nesneyi XML olarak seri hale getirme


292

Miras aldığım bir C # sınıfım var. Nesneyi başarılı bir şekilde "oluşturdum". Ama nesneyi XML serileştirmek gerekiyor. Bunu yapmanın kolay bir yolu var mı?

Sınıf serileştirme için ayarlanmış gibi görünüyor, ancak XML temsilini nasıl alacağından emin değilim. Sınıf tanımım şöyle:

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

İşte yapabileceğimi düşündüm, ama işe yaramıyor:

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

Bu nesnenin XML temsilini nasıl alabilirim?



1
Bunu başarmak için basit bir kütüphane geliştirdim: github.com/aishwaryashiva/SaveXML
Aishwarya Shiva

Yanıtlar:


511

XML serileştirme için XmlSerializer kullanmanız gerekir. Aşağıda örnek bir kod parçası bulunmaktadır.

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

10
Çizgisiz mükemmel çalışıyorXmlWriter writer = XmlWriter.Create(sww);
Paul Hunt

15
Yapmak biçimlendirilmiş tefrika nesneyi sağlamak için: XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented };yerineXmlWriter writer = XmlWriter.Create(sww);
Tono Nam

4
Yana XmlWriterkapsülü StringWriterdoğru, (gereksiz kullanılarak birinci) hem elden gerekmez? Ben XmlWriterbertaraf ilgileniyor
varsayalım

4
@talles XmlWriter, kapsüllemiyor, içeri girdiğinizi StringWriterkullanıyor StringWriterve atma beklentisi / sorumluluğu yok. Dahası StringWriter, XmlWriterkapsam dışında XmlWriter, imha edildiğinde yine de isteyebilirsiniz , XmlWriteratmak için kötü bir davranış olacaktır StringWriter. Genel bir kural olarak, imha edilmesi gereken bir şey beyan ederseniz, imha etmekten sorumlusunuz. Ve bu kurala göre, kendinizi beyan etmediğiniz hiçbir şey atmamalısınız. Yani her ikisi usingde gereklidir.
Arkaine55

3
System.Xml.Serialization kullanarak; System.IO kullanarak; System.Xml kullanarak;
timothy

122

Aşağıdaki gibi bir ref değişkeni kullanmak yerine bir dize döndürmek için mayın değiştirdim.

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

Kullanımı şöyle olurdu:

var xmlString = obj.Serialize();

8
çok güzel bir çözüm, bunu bir uzatma yöntemi olarak uygulama şeklinizi seviyorum
Spyros

57
Burada önerebileceğim bir şey var: try ... catch bloğunu kaldırın. Size herhangi bir fayda sağlamaz ve sadece atılan hatayı gizler.
jammycakes

7
Dizgi makinesinde de kullanmanıza gerek yok mu? örneğin: using (var stringWriter = new StringWriter ())
Steven Quick

3
@jammycakes Hayır! ExceptionOrada yeni bir attığınızda, StackTrace'i "Serialize <>" yöntemiyle genişletmiş olursunuz.
user11909

1
@ user2190035 Kesinlikle uzantısı yöntemi içinde kırmak olsaydı yığın izleme orada başlar? "Yığın izini genişletme" denemesi ile gereksiz görünüyor mu?
LeRoi

43

System.Xml ad alanını kullanarak XML kaydetme işlevi eklemek için aşağıdaki işlev herhangi bir nesneye kopyalanabilir.

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

Kaydedilen dosyadan nesne oluşturmak için aşağıdaki işlevi ekleyin ve [ObjectType] öğesini oluşturulacak nesne türüyle değiştirin.

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

writer.Flush()Bir de gereksiz usingbloğunun - writer'ın Dispose()yöntemi sizin için floş olacaktır.
bavaza

6
Deneyimlerim bunun doğru olmadığını buldu. Daha büyük verilerle using ifadesi, arabellek temizlenmeden önce akışı atacaktır. % 100 açıkça floş çağırmanızı öneririm.
Ben Gripka

6
writer.Flush () gereksiz DEĞİL, orada OLMALIDIR. Flush olmadan, verilerin bir kısmı hala StreamWriter arabelleğinde olabilir ve dosya atılır ve bazı veriler eksik olabilir.
Tomas Kubes

Kodunuzu çok beğendim: kısa ve temiz. Benim sorunum fonksiyonları tekrar tekrar farklı sınıflara kopyalama ile: bu kod çoğaltma değil mi? Diğer cevaplar benim kucaklayacağım şablon uzantısı yöntemleri ile genel kütüphane önerir. Ne düşünüyorsun?
Michael G

33

Uzantı sınıfı:

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

Kullanımı:

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

string xml = foo.Serialize();

Sadece bunu kullanmak istiyorum dosyasında uzantısı yöntemi tutan ad başvuru ve işe edeceğiz (bizim örneğimizde olurdu: using MyProj.Extensions;)

Uzantı yöntemini yalnızca belirli bir sınıfa (ör., Foo) Özgü hale getirmek istiyorsanız, uzantı yöntemindeki Tbağımsız değişkeni (ör.

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


31

Herhangi bir nesneden serileştirilmiş XML almak için aşağıdaki gibi işlevi kullanabilirsiniz.

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

Bunu istemciden çağırabilirsiniz.


21

Bir nesneyi serileştirmek için şunları yapın:

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

Ayrıca, XmlSerializer'ın çalışması için parametresiz bir kurucuya ihtiyacınız olduğunu unutmayın.


2
Bu beni deli ediyordu. Neden hep boş olduğunu anlayamadım. Sonra cevabınızı okuduktan sonra parametresiz bir kurucu olmadığımı fark ettim. Teşekkür ederim.
Andy

19

Ben Gripka'nın kopya cevabı ile başlayacağım:

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

Bu kodu daha önce kullandım. Ancak gerçeklik, bu çözümün biraz problemli olduğunu gösterdi. Genellikle programcıların çoğu, ayarları kaydetme ve serileştirme ayarlarını kaldırma sırasında serileştirir. Bu iyimser bir senaryodur. Serileştirme başarısız olduğunda, bazı nedenlerden dolayı, dosya kısmen yazılmıştır, XML dosyası tamamlanmamıştır ve geçersizdir. Sonuç olarak XML serileştirmesi çalışmaz ve uygulamanız başlangıçta kilitlenebilir. Dosya çok büyük değilse, önce dosyayı Dosyaya MemoryStreamyazmak için önce nesneyi serileştirmenizi öneririm . Bazı karmaşık özel serileştirmeler varsa bu durum özellikle önemlidir. Hiçbir zaman tüm vakaları test edemezsiniz.

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

Gerçek dünya senaryosundaki serileştirme, bozuk serileştirme dosyasıyla sayılmalıdır, bazen gerçekleşir. Ben Gripka tarafından sağlanan yük fonksiyonu gayet iyi.

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

Ve bazı kurtarma senaryosu ile tamamlanabilir. Sorun olması durumunda silinebilen ayar dosyaları veya diğer dosyalar için uygundur.

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

MemoryStream'i bir dosyaya yazarken işlemin kesilmesi mümkün değil mi, örneğin bir güç kesintisi ile?
John Smith

1
Evet mümkün. Ayarları geçici bir dosyaya yazıp orijinali değiştirerek bundan kaçınabilirsiniz.
Tomas Kubes

19

Yukarıda verilen tüm cevaplar doğrudur. Bu sadece en basit sürüm:

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

9

ToStringSınıfın yöntemini çağırmaktan biraz daha karmaşık , ama fazla değil.

İşte herhangi bir nesne türünü serileştirmek için kullanabileceğiniz basit bir bırakma işlevi. Serileştirilmiş XML içeriğini içeren bir dize döndürür:

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


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

Sonucu istediğiniz yerde xml dosyası olarak oluşturabilir ve saklayabilirsiniz.


4

iş kodum. Utf8 xml enable boş ad alanını döndürür .

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

Örnek yanıt verir Yandex api ödeme 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" />

4

C # kullanarak XML bir nesneyi serileştirmek için basit bir yolu var, harika çalışıyor ve son derece yeniden kullanılabilir. Bu eski bir iş parçacığı olduğunu biliyorum, ama birisi bu yararlı olabilir bulabilirsiniz çünkü bunu göndermek istedim.

Ben yöntemi şöyle çağırıyorum:

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

İşte işi yapan sınıf:

Not: Bunlar uzantı yöntemleri olduğundan statik bir sınıfta olmaları gerekir.

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

4

Yukarıdaki çözümlere dayanarak, herhangi bir nesneyi serileştirmek ve serisini kaldırmak için kullanabileceğiniz bir uzantı sınıfı gelir. Diğer XML nitelikleri size bağlıdır.

Sadece şu şekilde kullanın:

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

2

Veya bu yöntemi nesnenize ekleyebilirsiniz:

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

1

İşte Cml nesnelerini xml'ye serileştirmeye yardımcı olacak temel bir kod:

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

6
Bu kodun kaynağını belirtmeniz iyi olur: 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)

Aşağıdaki sınıfları kullanmanız gerekir:

using System.IO;
using System.Xml;
using System.Xml.Serialization;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.