将对象转换为XML字符串

115

我有一个名为 WebserviceType 的类,是从一个XSD文件使用xsd.exe工具获取的。

现在我想将 WebServiceType 对象的实例反序列化成字符串。如何做到这一点?

MethodCheckType 对象的参数是一个 WebServiceType 数组。

我的第一次尝试就像我序列化它一样:使用 XmlSerializerStringWriter(在序列化时我使用了一个 StringReader)。

这是我序列化 WebServiceType 对象的方法:

XmlSerializer serializer = new XmlSerializer(typeof(MethodCheckType));
        MethodCheckType output = null;
        StringReader reader = null;

        // catch global exception, logg it and throw it
        try
        {
            reader = new StringReader(path);
            output = (MethodCheckType)serializer.Deserialize(reader);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            reader.Dispose();
        }

        return output.WebService;

编辑:

也许我可以用不同的话来说:我有一个 MethodCheckType 对象的实例,另一方面我有从中序列化此对象的 XML 文档。现在我想将此实例转换为 XML 文档,以字符串形式呈现。然后我必须验证两个 XML 文档字符串是否相同。这是我必须做的,因为我对第一个方法进行单元测试,在该方法中,我将一个 XML 文档读入 StringReader 中,并将其序列化为一个 MethodCheckType 对象。


2
你遇到了什么错误?你可能混淆了术语:在 XML 世界中,序列化是将对象转换为 XML;反序列化是将 XML 转换为对象。你想要从 XML 字符串反序列化一个对象吗? - carlosfigueira
5个回答

239

以下是双向转换的方法。 this = 您的类的实例

public string ToXML()
    {
        using(var stringwriter = new System.IO.StringWriter())
        { 
            var serializer = new XmlSerializer(this.GetType());
            serializer.Serialize(stringwriter, this);
            return stringwriter.ToString();
        }
    }

 public static YourClass LoadFromXMLString(string xmlText)
    {
        using(var stringReader = new System.IO.StringReader(xmlText))
        {
            var serializer = new XmlSerializer(typeof(YourClass ));
            return serializer.Deserialize(stringReader) as YourClass ;
        }
    }

15
为正确释放资源,你应该使用“using”模式或调用“Dispose”方法。 - Ivan Kochurkin
你必须确保在所有CLR版本中不使用非托管代码。 - AlphaOmega
3
为什么?因为您应该处理所有资源密集型的内容(托管和非托管)。仅仅因为垃圾回收器会(最终)为您清理,不意味着您应该使其工作过度困难。在进行操作时进行清理,您的代码将更加高效。[在此处查看有关显式处理的原因的更多信息](https://dev59.com/K3RB5IYBdhLWcg3wuZU1#538193) - Liam
1
你们正在讨论如何处理 StringWriter 和 StringReader(因为 XmlSerializer 没有 Dispose 方法)。 - symbiont
函数的结尾释放资源和使用 using 一样高效,不是吗?@KvanTTT? - Mark Entingh

91

我知道这是一个非常旧的帖子,但在看了L.B的回复后,我思考如何改进已接受的答案并将其变得更通用以适用于我自己的应用程序。以下是我的想法:

public static string Serialize<T>(T dataToSerialize)
{
    try
    {
        var stringwriter = new System.IO.StringWriter();
        var serializer = new XmlSerializer(typeof(T));
        serializer.Serialize(stringwriter, dataToSerialize);
        return stringwriter.ToString();
    }
    catch
    {
        throw;
    }
}

public static T Deserialize<T>(string xmlText)
{
    try
    {
        var stringReader = new System.IO.StringReader(xmlText);
        var serializer = new XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(stringReader);
    }
    catch
    {
        throw;
    }
}

现在这些方法可以放在一个静态的帮助类中,这意味着不需要将代码重复到每个需要序列化的类中。

10
在“Serialize”方法中,使用 dataToSerialize.GetType() 代替 typeof(T)。乍一看,使用 T 作为类型似乎是安全的,但如果“dataToSerialize”对象已被强制转换为父类型(ChildClass 转换为 BaseClass),它将抛出错误。当然,首先要检查其是否为空。 - Paul Easter
2
捕获异常却什么都不做只是为了重新引发它有何意义? - crush
1
很好的问题;我并不是在这里尝试开发完整的图像,只是功能框架,而且我绝对不想给出一个吞噬异常的例子。当时似乎是一个不错的通用替代方案。欢迎提出改进建议! - William Smith
好的可重用解决方案。 - Nitesh Saxena
1
try catch 块完全是多余的,应该从本来是一个很好的例子中删除。 - Ste Brown

23
    public static string Serialize(object dataToSerialize)
    {
        if(dataToSerialize==null) return null;

        using (StringWriter stringwriter = new System.IO.StringWriter())
        {
            var serializer = new XmlSerializer(dataToSerialize.GetType());
            serializer.Serialize(stringwriter, dataToSerialize);
            return stringwriter.ToString();
        }
    }

    public static T Deserialize<T>(string xmlText)
    {
        if(String.IsNullOrWhiteSpace(xmlText)) return default(T);

        using (StringReader stringReader = new System.IO.StringReader(xmlText))
        {
            var serializer = new XmlSerializer(typeof(T));
            return (T)serializer.Deserialize(stringReader);
        }
    }

1
Serialize不需要泛型。Object就足够了。 if(dataToSerialize==null) return null; ... var serializer = new XmlSerializer(dataToSerialize.GetType()); ... - AlphaOmega

1
 public static class XMLHelper
    {
        /// <summary>
        /// Usage: var xmlString = XMLHelper.Serialize<MyObject>(value);
        /// </summary>
        /// <typeparam name="T">Kiểu dữ liệu</typeparam>
        /// <param name="value">giá trị</param>
        /// <param name="omitXmlDeclaration">bỏ qua declare</param>
        /// <param name="removeEncodingDeclaration">xóa encode declare</param>
        /// <returns>xml string</returns>
        public static string Serialize<T>(T value, bool omitXmlDeclaration = false, bool omitEncodingDeclaration = true)
        {
            if (value == null)
            {
                return string.Empty;
            }
            try
            {
                var xmlWriterSettings = new XmlWriterSettings
                {
                    Indent = true,
                    OmitXmlDeclaration = omitXmlDeclaration, //true: remove <?xml version="1.0" encoding="utf-8"?>
                    Encoding = Encoding.UTF8,
                    NewLineChars = "", // remove \r\n
                };

                var xmlserializer = new XmlSerializer(typeof(T));

                using (var memoryStream = new MemoryStream())
                {
                    using (var xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
                    {
                        xmlserializer.Serialize(xmlWriter, value);
                        //return stringWriter.ToString();
                    }

                    memoryStream.Position = 0;
                    using (var sr = new StreamReader(memoryStream))
                    {
                        var pureResult = sr.ReadToEnd();
                        var resultAfterOmitEncoding = ReplaceFirst(pureResult, " encoding=\"utf-8\"", "");
                        if (omitEncodingDeclaration)
                            return resultAfterOmitEncoding;
                        return pureResult;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("XMLSerialize error: ", ex);
            }
        }

        private static string ReplaceFirst(string text, string search, string replace)
        {
            int pos = text.IndexOf(search);

            if (pos < 0)
            {
                return text;
            }

            return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
        }
    }

0
这是我的解决方案,对于任何列表对象,您都可以使用此代码将其转换为XML布局。 KeyFather是您的主要标记,KeySon是开始循环的位置。
public string BuildXml<T>(ICollection<T> anyObject, string keyFather, string keySon)
    {
        var settings = new XmlWriterSettings
        {
            Indent = true
        };
        PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
        StringBuilder builder = new StringBuilder();
        using (XmlWriter writer = XmlWriter.Create(builder, settings))
        {
            writer.WriteStartDocument();
            writer.WriteStartElement(keyFather);
            foreach (var objeto in anyObject)
            {
                writer.WriteStartElement(keySon);
                foreach (PropertyDescriptor item in props)
                {
                    writer.WriteStartElement(item.DisplayName);
                    writer.WriteString(props[item.DisplayName].GetValue(objeto).ToString());
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            writer.WriteFullEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            return builder.ToString();
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接