将对象序列化为XML


292

我有一个继承的C#类。我已经成功“构建”了对象。但是我需要将该对象序列化为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表示形式?



1
我开发了一个简单的库来实现这一目标:github.com/aishwaryashiva/SaveXML
Aishwarya Shiva

Answers:


509

您必须使用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
     }
 }

10
似乎无限制地工作得很好XmlWriter writer = XmlWriter.Create(sww);
Paul Hunt 2014年

15
要格式化序列化的对象,请执行以下操作:XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented };代替XmlWriter writer = XmlWriter.Create(sww);
Tono Nam

4
由于XmlWriter封装了StringWriter您,因此您无需将两者都处置(第一次使用是多余的),对吗?我假设XmlWriter要处理

4
@talles XmlWriter没有封装StringWriter,它正在利用您传入的内容,StringWriter并且没有期望/负责处理它。再者StringWriter不在XmlWriter范围之内,您在XmlWriter配置时仍可能会想要它,因为XmlWriter配置您的行为会很差StringWriter。通常,如果您声明需要处置的东西,则您有责任处置它。对于该规则而言,任何不声明自己的内容都不应该处置。因此,两个using都是必需的。
Arkaine55

3
使用System.Xml.Serialization; 使用System.IO; 使用System.Xml;
蒂莫西

122

我修改了我的方法以返回字符串,而不是像下面这样使用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();

8
非常好的解决方案,我喜欢您将其实现为扩展方法的方式
Spyros

57
我在这里建议的一件事:删除try ... catch块。它并没有给您带来任何好处,而只是模糊了所引发的错误。
jammycakes 2014年

7
您是否还不需要在字符串编写器上使用?例如:using(var stringWriter = new StringWriter())
Steven Quick

3
@jammycakes不!当您Exception在其中放置新对象时,已使用“ Serialize <>”方法扩展了StackTrace。
user11909

1
@ user2190035确定要在扩展方法内中断时,堆栈跟踪是否将从此处开始?尝试进行“扩展堆栈跟踪”似乎没有必要吗?
LeRoi

42

可以将以下函数复制到任何对象,以使用System.Xml命名空间添加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];
    }
}

writer.Flush()在一个using块中是多余的- writerDispose()方法将为您刷新它。
bavaza 2015年

6
我的经验发现事实并非如此。对于较大的数据,using语句将在清除缓冲区之前处理流。我100%建议明确调用冲洗。
Ben Gripka'3

6
writer.Flush()不是多余的,它必须存在。如果不使用Flush,则可能会发生部分数据仍在StreamWriter缓冲区中并且文件被处置并且某些数据丢失的情况。
Tomas Kubes,2015年

我非常喜欢您的代码:简洁明了。我的问题是一次又一次地将函数复制到不同的类:是不是代码重复?其他答案建议我将接受带有模板扩展方法的通用库。你怎么看?
Michael G

33

扩展类:

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

只需在要使用扩展名的文件中引用保留扩展名方法的名称空间,它就会起作用(在我的示例中为: using MyProj.Extensions;

请注意,如果您想使扩展方法仅特定于特定的类(例如Foo),则可以替换T扩展方法中的参数,例如。

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


31

您可以使用下面的函数从任何对象获取序列化的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;
    }
}

您可以从客户端调用它。


21

要序列化对象,请执行以下操作:

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

还请记住,要使XmlSerializer正常工作,您需要一个无参数的构造函数。


2
这让我发疯。我不知道为什么它总是空白。然后意识到在阅读您的答案后我没有没有参数的构造函数。谢谢。
安迪

19

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

我之前使用过此代码。但是现实表明,这种解决方案有点问题。通常,大多数程序员只是在保存时序列化设置,在加载时反序列化设置。这是一个乐观的情况。一旦序列化失败,由于某种原因,该文件将被部分写入,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();
    }
}

将MemoryStream写入文件时,例如通过断电,是否可能会中断进程?
约翰·史密斯,

1
是的,有可能。您可以通过将设置写入临时文件然后替换原始文件来避免这种情况。
Tomas Kubes,

18

以上所有建议的答案都是正确的。这只是最简单的版本:

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

9

它比调用 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;
    }
}


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

您可以将结果创建为xml文件并将其存储在所需位置。


4

我的工作代码。返回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" />

4

我有一种使用C#将对象序列化为XML的简单方法,它工作得很好并且具有很高的可重用性。我知道这是一个较旧的主题,但是我想发布此主题,因为有人可能认为这对他们有帮助。

这是我所谓的方法:

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

这是完成工作的课程:

注意:由于这些是扩展方法,因此它们必须在静态类中。

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

基于上述解决方案,这里有一个扩展类,您可以使用该扩展类对任何对象进行序列化和反序列化。任何其他XML归因取决于您。

像这样使用它:

        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

或者,您可以将此方法添加到对象中:

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

1

以下是基本代码,可帮助将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();
   }
}    

6
这将是很好,如果你举这个代码的来源: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)

您需要使用以下类:

using System.IO;
using System.Xml;
using System.Xml.Serialization;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.