2010-11-08 167 views
187

我有一個繼承的C#類。我已經成功「構建」了這個對象。但我需要將對象序列化爲XML。有沒有簡單的方法來做到這一點?將對象序列化爲XML

它看起來像類已設置了序列化,但我不知道如何讓XML表示。我的類定義是這樣的:

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

這是我想我能做到,但它不工作:

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

我如何獲得此對象的XML表示?

+0

我開發了一個簡單的庫做實現這一點:https://github.com/aishwaryashiva/SaveXML – 2015-08-28 14:03:51

+0

另請參閱:XML序列化和反序列化在CodeProject](http://www.codeproject.com/Articles/487571/XML-Serializ通貨膨脹-和反序列化-部分) – 2014-09-14 14:59:19

回答

338

你必須使用XmlSerializer的用於XML序列化。以下是一個示例代碼片段。

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

似乎沒有行'XmlWriter的作家= XmlWriter.Create(SWW),以很好地工作;'' – 2014-06-27 10:52:21

+105

人using'使用'using's!處理這些對象! – Liam 2014-09-11 16:25:25

+8

要序列化的對象格式化:''XmlTextWriter writer = new XmlTextWriter(sww){Formatting = Formatting.Inpression};''而不是'XmlWriter writer = XmlWriter.Create(sww);' – 2015-06-21 15:22:33

13

序列化一個對象,這樣做:

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

還記得那對XmlSerializer的工作,你需要一個參數的構造函數。

+1

這讓我瘋狂。我無法弄清楚它爲什麼總是空白。然後在閱讀你的答案後意識到我沒有沒有參數的構造函數。謝謝。 – Andy 2017-01-23 19:45:31

6

它比調用類的ToString方法更復雜一點,但不多。

這裏有一個簡單的插入式功能,您可以使用序列化的任何類型的對象。它返回一個包含序列化XML內容的字符串:

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

您可以使用下面的函數從任何對象獲取序列化的XML。

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

您可以從客戶端調用此函數。

28

下面的函數可以被複制到任何對象添加一個XML使用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(); 
    } 
} 

要從保存的文件創建對象,請添加以下函數,並用要創建的對象類型替換[ObjectType]。

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

'writer.Flush()'在'using'塊中是多餘的'''''''''Dispose()'方法將爲您刷新。 – bavaza 2015-03-13 10:38:19

+1

我的經驗發現並非如此。對於更大的數據,using語句將在清除緩衝區之前處理該流。我100%建議明確調用刷新。 – 2015-03-14 05:27:26

+1

writer.Flush()不是多餘的,它必須在那裏。如果沒有刷新,可能會發生部分數據仍在StreamWriter緩衝區中,並且文件被丟棄並且某些數據丟失。 – qub1n 2015-11-14 20:49:46

79

我修改了mine來返回一個字符串,而不是像下面那樣使用ref變量。

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

它的用法是這樣的:

var xmlString = obj.Serialize(); 
+7

非常好的解決方案,我喜歡你作爲擴展方法實現這個方法 – Spyros 2013-08-30 11:38:01

+34

我在這裏建議的一件事:刪除try ... catch塊。它沒有給你帶來任何好處,只是模糊了正在拋出的錯誤。 – jammycakes 2014-10-20 10:50:20

+1

難道你不需要使用串口打字機嗎?例如:使用(var stringWriter = new StringWriter()) – 2015-08-13 00:57:20

23

擴展類:

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

用法:

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

string xml = foo.Serialize(); 

只是引用該命名空間牽着你的擴展方法在你想要的文件o使用它,它會工作(在我的例子中,它將是:using MyProj.Extensions;

請注意,如果您想使擴展方法僅針對特定類(例如,Foo),您可以將T參數在擴展方法中,例如。

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

+0

我試過這段代碼,因爲它看起來是最乾淨的,但在最後一行它沒有提供「Serialize()」方法。我錯過了什麼? – ditto1977 2014-12-26 15:29:56

+0

@ user312305我最真誠的道歉,我發佈了錯誤的版本。請看我編輯的答案,不需要繼承,它只適用於所有對象! – 2014-12-26 16:29:21

+0

非常好,我的朋友!現在我只使用'XmlExtension.Serialize(foo);'一切都很好!非常感謝。 – ditto1977 2014-12-26 17:16:20

1

或者你可以將這個方法添加到您的對象:

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

我將開始與本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(); 
    } 
} 

我這個代碼之前使用。但現實表明,這個解決方案有點問題。通常,大多數程序員只是在載入時序列化保存和反序列化設置。這是一個樂觀的情景。一旦序列化失敗,由於某種原因,文件被部分寫入,XML文件不完整,並且是無效的。因此,XML反序列化不起作用,您的應用程序可能會在開始時崩潰。如果文件不是很大,我建議首先將對象序列化爲MemoryStream,然後將流寫入文件。如果有一些複雜的自定義序列化,這種情況尤其重要。你永遠不能測試所有的情況。

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

在現實世界中的場景應該與損壞的序列號文件數的反序列化,它的某個時候發生。 Ben Gripka提供的加載功能很好。

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

它可以被一些恢復場景包裝。它適用於設置文件或其他可以在出現問題時刪除的文件。

public static [ObjectType] LoadWithRecovery(string fileName) 
{ 
    try 
    { 
     return Load(fileName); 
    } 
    catch(Excetion) 
    { 
     File.Delete(fileName); //delete corrupted settings file 
     return GetFactorySettings(); 
    } 
} 
2
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(); 

您可以創建並存儲結果作爲在所需位置xml文件。

1

我的工作代碼。返回utf8 xml啓用空名稱空間。

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

示例返回響應Yandex的API金說Aviso網址:

<?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" /> 
0

這是一個基本的代碼,這將有助於序列化的C#對象轉換爲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(); 
    } 
}