将对象序列化为XML

use*_*166 264 c# xml-serialization

我有一个我继承的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
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

这是我认为我可以做的,但它不起作用:

MyObject o = new MyObject();
// Set o properties
string xml = o.ToString();
Run Code Online (Sandbox Code Playgroud)

如何获取此对象的XML表示?

Ram*_*Vel 469

您必须使用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
     }
 }
Run Code Online (Sandbox Code Playgroud)

  • 要使序列化对象格式化,请执行:`XmlTextWriter writer = new XmlTextWriter(sww){Formatting = Formatting.Indented};`而不是`XmlWriter writer = XmlWriter.Create(sww);` (13认同)
  • 如果没有`XmlWriter writer = XmlWriter.Create(sww)行,似乎工作得非常好;` (10认同)
  • 使用 System.Xml.Serialization;使用 System.IO;使用 System.Xml; (5认同)
  • @talles`XmlWriter`没有封装`StringWriter`,它正在利用你传入的`StringWriter`并且没有期望/责任处理它.进一步`StringWriter`在`XmlWriter`的范围之外,当你放置`XmlWriter`时你可能仍然需要它,`XmlWriter`处理你的`StringWriter`会是不好的行为.作为一般规则,如果您声明需要处置的东西,则您有责任处置它.并且隐含于该规则,任何你不宣称自己不应该处置的东西.所以'使用'都是必要的. (4认同)
  • 由于`XmlWriter`封装了`StringWriter`,所以你不需要同时处理它们(第一次使用是冗余的),对吧?我假设`XmlWriter`负责处理它...... (3认同)
  • @talles 现在可以在 Github 上的 .NET Core 代码库中进行验证。XmlWriter 不会处理基础 StringWriter。 (2认同)

Kwe*_*wex 112

我修改了我的返回字符串,而不是像下面那样使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

它的用法如下:

var xmlString = obj.Serialize();
Run Code Online (Sandbox Code Playgroud)

  • 我在这里建议的一件事是:删除try ... catch块.它没有给你任何好处,只是混淆了被抛出的错误. (52认同)
  • 非常好的解决方案,我喜欢你实现这个作为扩展方法的方式 (8认同)
  • 你不也需要在字符写作器上使用吗?例如:using(var stringWriter = new StringWriter()) (6认同)
  • @jammycakes不!当你在那里抛出一个新的`Exception`时,你已经使用方法"Serialize <>"扩展了StackTrace. (2认同)

Ben*_*pka 40

可以使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

要从保存的文件创建对象,请添加以下函数,并将[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];
    }
}
Run Code Online (Sandbox Code Playgroud)

  • writer.Flush()不是多余的,它必须在那里.如果没有Flush,可能会发生部分数据仍在StreamWriter缓冲区中并且文件被丢弃并且一些数据丢失. (6认同)
  • 我的经验发现这不是真的.对于较大的数据,using语句将在清除缓冲区之前处理流.我100%建议明确调用flush. (5认同)

Ale*_*ert 31

扩展类:

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();
                }    
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

string xml = foo.Serialize();
Run Code Online (Sandbox Code Playgroud)

只是引用该命名空间牵着你的扩展方法在文件中,你想在使用它,它会工作(在我的例子那就是:using MyProj.Extensions;)

请注意,如果要使扩展方法仅针对特定类(例如,Foo),则可以替换T扩展方法中的参数,例如.

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


Imr*_*rul 29

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

您可以从客户端调用此方法.


Rox*_*Rox 18

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

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

还要记住,要使XmlSerializer工作,您需要一个无参数构造函数.

  • 这让我疯了.我无法弄清楚为什么它总是空白.然后意识到我在阅读你的答案后没有一个没有参数的构造函数.谢谢. (2认同)

Tom*_*bes 18

我将从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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

现实世界场景中的反序列化应该与损坏的序列化文件一起计算,它会在某个时间发生.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];        
    }    
}
Run Code Online (Sandbox Code Playgroud)

它可以被一些恢复方案包裹起来.它适用于设置文件或其他可在出现问题时删除的文件.

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


avj*_*avj 9

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

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


Cod*_*ray 8

它比调用ToString类的方法要复杂一点,但并不多.

这是一个简单的drop-in函数,可用于序列化任何类型的对象.它返回一个包含序列化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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Tyl*_*sza 7

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

这是我调用该方法的方式:

var objectToSerialize = new MyObject();
var xmlString = objectToSerialize.ToXmlString();
Run Code Online (Sandbox Code Playgroud)

这是完成工作的类:

注意:由于这些是扩展方法,因此它们需要位于静态类中。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Hef*_*s68 6

基于上述解决方案,这里有一个扩展类,您可以使用它来序列化和反序列化任何对象。任何其他 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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Aam*_*mir 5

这是一个关于如何做到这一点的好教程

你应该基本上使用System.Xml.Serialization.XmlSerializer类来做到这一点。


dev*_*ria 5

我的工作代码。返回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;
}
Run Code Online (Sandbox Code Playgroud)

示例返回响应 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" />
Run Code Online (Sandbox Code Playgroud)