如何编写将List <t>转换为xml字符串的通用方法

时间:2016-01-04 17:53:34

标签: c# xml generics

我从网站http://www.dotnetcurry.com/ShowArticle.aspx?ID=428

获得了例程

查看他们的代码

class Program
    {
        static void Main(string[] args)
        {
            List<Employee> empList = new List<Employee>();
            empList.Add(new Employee() { ID = 1, FName = "John", LName = "Shields", DOB = DateTime.Parse("12/11/1971"), Sex = 'M' });
            empList.Add(new Employee() { ID = 2, FName = "Mary", LName = "Jacobs", DOB = DateTime.Parse("01/17/1961"), Sex = 'F' });
            empList.Add(new Employee() { ID = 3, FName = "Amber", LName = "Agar", DOB = DateTime.Parse("12/23/1971"), Sex = 'M' });
            empList.Add(new Employee() { ID = 4, FName = "Kathy", LName = "Berry", DOB = DateTime.Parse("11/15/1976"), Sex = 'F' });
            empList.Add(new Employee() { ID = 5, FName = "Lena", LName = "Bilton", DOB = DateTime.Parse("05/11/1978"), Sex = 'F' });
        }
    }

    class Employee
    {
        public int ID { get; set; }
        public string FName { get; set; }
       public string LName { get; set; }
        public DateTime DOB { get; set; }
        public char Sex { get; set; }
    }

如果有人看到这个代码区域从列表生成xml,那么必须注意代码不是通用的,而是依赖于List。 我想要一个可以将任何列表转换为xml的通用例程。特别是如果我可以通过扩展方法做。

try
{
    var xEle = new XElement("Employees",
                from emp in empList
                select new XElement("Employee",
                             new XAttribute("ID", emp.ID),
                               new XElement("FName", emp.FName),
                               new XElement("LName", emp.LName),
                               new XElement("DOB", emp.DOB),
                               new XElement("Sex", emp.Sex)
                           ));

    xEle.Save("D:\\employees.xml");
    Console.WriteLine("Converted to XML");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}
Console.ReadLine();
寻求帮助。感谢

修改

我只是稍微定制ToXml(),但为什么会抛出错误?任何想法?

public static class utility
{
    public static string ToXml<T>(this T obj, string strContainer = "")
    {
        XmlSerializer serialize = null;

        if (strContainer.Trim() == "")
            serializer = new XmlSerializer(typeof(T));
        else
            serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(strContainer));

        using (StringWriter sw = new StringWriter())
        {
            serializer.Serialize(sw, obj);
            return sw.ToString();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

看看你是否可以使用这个通用扩展

public static string ToXml<T>(this T obj)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    using (StringWriter sw = new StringWriter())
    {
        serializer.Serialize(sw, obj);
        return sw.ToString();
    }
}

一样使用它
var xmlString = empList.ToXml();

使用您的代码生成此XML

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfEmployee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Employee>
    <ID>1</ID>
    <FName>John</FName>
    <LName>Shields</LName>
    <DOB>1971-12-11T00:00:00</DOB>
    <Sex>77</Sex>
  </Employee>
  <Employee>
    <ID>2</ID>
    <FName>Mary</FName>
    <LName>Jacobs</LName>
    <DOB>1961-01-17T00:00:00</DOB>
    <Sex>70</Sex>
  </Employee>
</ArrayOfEmployee>

修改

使用自定义根元素名称&amp;删除命名空间,使用此重载

public static string ToXml<T>(this T obj, string rootName)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(rootName));

    var xmlNs = new XmlSerializerNamespaces();
    xmlNs.Add(string.Empty, string.Empty);

    using (StringWriter sw = new StringWriter())
    {
        serializer.Serialize(sw, obj, xmlNs);
        return sw.ToString();
    }
}

哪个产生

<?xml version="1.0" encoding="utf-16"?>
<Employees>
  <Employee>
    <ID>1</ID>
    <FName>John</FName>
    <LName>Shields</LName>
    <DOB>1971-12-11T00:00:00</DOB>
    <Sex>77</Sex>
  </Employee>
  <Employee>
    <ID>2</ID>
    <FName>Mary</FName>
    <LName>Jacobs</LName>
    <DOB>1961-01-17T00:00:00</DOB>
    <Sex>70</Sex>
  </Employee>
</Employees>

答案 1 :(得分:1)

您可以使用XmlSerializer默认情况下可以序列化公共字段,并可以attributes进行自定义。演示场景的最简单示例如下所示:

static void Main(string[] args)
{
    List<Employee> empList = new List<Employee>();
    empList.Add(new Employee() { ID = 1, FName = "John", LName = "Shields", DOB = DateTime.Parse("12/11/1971"), Sex = 'M' });
    empList.Add(new Employee() { ID = 2, FName = "Mary", LName = "Jacobs", DOB = DateTime.Parse("01/12/1961"), Sex = 'F' });
    empList.Add(new Employee() { ID = 3, FName = "Amber", LName = "Agar", DOB = DateTime.Parse("05/12/1971"), Sex = 'M' });
    empList.Add(new Employee() { ID = 4, FName = "Kathy", LName = "Berry", DOB = DateTime.Parse("11/06/1976"), Sex = 'F' });
    empList.Add(new Employee() { ID = 5, FName = "Lena", LName = "Bilton", DOB = DateTime.Parse("05/11/1978"), Sex = 'F' });

    XmlSerializer serializer = new XmlSerializer(empList.GetType());
    serializer.Serialize(Console.Out, empList);

    Console.ReadKey();
}

此示例将显示下一个结果:

<?xml version="1.0" encoding="cp866"?>
<ArrayOfEmployee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd
="http://www.w3.org/2001/XMLSchema">
  <Employee>
    <ID>1</ID>
    <FName>John</FName>
    <LName>Shields</LName>
    <DOB>1971-11-12T00:00:00</DOB>
    <Sex>77</Sex>
  </Employee>
  <Employee>
    <ID>2</ID>
    <FName>Mary</FName>
    <LName>Jacobs</LName>
    <DOB>1961-12-01T00:00:00</DOB>
    <Sex>70</Sex>
  </Employee>
  <Employee>
    <ID>3</ID>
    <FName>Amber</FName>
    <LName>Agar</LName>
    <DOB>1971-12-05T00:00:00</DOB>
    <Sex>77</Sex>
  </Employee>
  <Employee>
    <ID>4</ID>
    <FName>Kathy</FName>
    <LName>Berry</LName>
    <DOB>1976-06-11T00:00:00</DOB>
    <Sex>70</Sex>
  </Employee>
  <Employee>
    <ID>5</ID>
    <FName>Lena</FName>
    <LName>Bilton</LName>
    <DOB>1978-11-05T00:00:00</DOB>
    <Sex>70</Sex>
  </Employee>
</ArrayOfEmployee>

通用实现将更简单并基于预期的结果类型。我正在使用此代码:

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace Rikrop.Core.Serialization.Xml
{
    public static class XmlSerializers
    {
        private static readonly ConcurrentDictionary<Type, XmlSerializer> serializers = new ConcurrentDictionary<Type, XmlSerializer>();
        private static readonly XmlSerializerNamespaces xns = new XmlSerializerNamespaces();
        private static readonly UTF8Encoding defaultEncoding = new UTF8Encoding(false);

        static XmlSerializers()
        {
            xns.Add("", "");
        }

        private static XmlSerializer GetSerializer(Type type, XmlRootAttribute xmlRoot = null)
        {
            return serializers.GetOrAdd(type, t => new XmlSerializer(t, xmlRoot));
        }

        public static byte[] SerializeToBytes<T>(T obj, bool omitXmlDeclaration = true, string customRootName = null, bool omitNamespaces = true, Encoding encoding = null)
        {
            if (ReferenceEquals(null, obj))
                return null;
            using (var ms = new MemoryStream())
            {
                var xmlSettings = new XmlWriterSettings
                {
                    OmitXmlDeclaration = omitXmlDeclaration,
                    NewLineHandling = NewLineHandling.Entitize,
                    Indent = true,
                    Encoding = encoding ?? defaultEncoding
                };
                using (var xmlWriter = XmlWriter.Create(ms, xmlSettings))
                {
                    var xmlRootNameAttribute = string.IsNullOrEmpty(customRootName) ? null : new XmlRootAttribute(customRootName);
                    GetSerializer(typeof(T), xmlRootNameAttribute).Serialize(xmlWriter, obj, omitNamespaces ? xns : null);
                    return ms.ToArray();
                }
            }
        }

        public static string Serialize<T>(T obj, bool omitNamespaces = true, Encoding encoding = null, bool omitXmlDeclaration = true, string customRootName = null)
        {
            var bytes = SerializeToBytes(obj, omitXmlDeclaration, customRootName, omitNamespaces, encoding);
            return (encoding ?? defaultEncoding).GetString(bytes);
        }

        public static string SafeSerialize<T>(T obj, bool omitNamespaces = true, Encoding encoding = null, bool omitXmlDeclaration = true, string customRootName = null)
        {
            try
            {
                return Serialize(obj, omitNamespaces, encoding, omitXmlDeclaration, customRootName);
            }
            catch (Exception e)
            {
                // log error here
            }
            return null;
        }

        public static T SafeDeserialize<T>(byte[] serializedData, Encoding encoding = null, bool silentMode = false)
            where T : class 
        {
            try
            {
                return DeserializeFromBytes<T>(serializedData, encoding);
            }
            catch (Exception e)
            {
                if (!silentMode)
                {
                    // log error here
                }
            }
            return null;
        }

        public static T SafeDeserialize<T>(string serializedData, Encoding encoding = null, bool silentMode = false)
            where T : class
        {
            try
            {
                return Deserialize<T>(serializedData, encoding);
            }
            catch (Exception e)
            {
                if (!silentMode)
                {
                    // log error here
                }
            }
            return null;
        }

        public static T DeserializeFromBytes<T>(byte[] serializedData, Encoding encoding = null) where T : class
        {
            using (var sr = new StreamReader(new MemoryStream(serializedData), encoding ?? defaultEncoding))
            using (var xmlReader = XmlReader.Create(sr))
                return (T) GetSerializer(typeof(T)).Deserialize(xmlReader);
        }

        public static T Deserialize<T>(string stringData, Encoding encoding = null) where T : class
        {
            var bytes = (encoding ?? defaultEncoding).GetBytes(stringData);
            return DeserializeFromBytes<T>(bytes, encoding);
        }
    }
}

对于字节数组的序列化我使用上面的简短版本代码:

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace Rikrop.Core.Serialization.Xml
{
    public static class XmlSerializers
    {
        private static readonly ConcurrentDictionary<Type, XmlSerializer> serializers = new ConcurrentDictionary<Type, XmlSerializer>();
        private static readonly XmlSerializerNamespaces xnameSpace = new XmlSerializerNamespaces();
        private static readonly UTF8Encoding defaultEncoding = new UTF8Encoding(false);

        static XmlSerializers()
        {
            xnameSpace.Add("", "");
        }

        private static XmlSerializer GetSerializer(Type type)
        {
            return serializers.GetOrAdd(type, t => new XmlSerializer(t));
        }

        public static byte[] Serialize(object obj, bool omitNamespaces = false, Encoding encoding = null)
        {
            if (ReferenceEquals(null, obj))
                return null;
            using (var stream = new MemoryStream())
            {
                using (var xmlWriter = XmlWriter.Create(stream, new XmlWriterSettings { OmitXmlDeclaration = false, Encoding = encoding ?? defaultEncoding, Indent = true}))
                {
                    GetSerializer(obj.GetType()).Serialize(xmlWriter, obj, omitNamespaces ? xnameSpace : null);
                    return stream.ToArray();
                }
            }
        }

        public static string SerializeToString(object obj, bool omitNamespaces = false, Encoding encoding = null)
        {
            var bytes = Serialize(obj, omitNamespaces, encoding);
            return (encoding ?? defaultEncoding).GetString(bytes);
        }

        public static TData Deserialize<TData>(byte[] serializedData, Encoding encoding = null) where TData : class
        {
            using (var sr = new StreamReader(new MemoryStream(serializedData), encoding ?? defaultEncoding))
            using (var xmlReader = XmlReader.Create(sr))
                return (TData)GetSerializer(typeof(TData)).Deserialize(xmlReader);
        }

        public static TData DeserializeFromString<TData>(string stringData, Encoding encoding = null) where TData : class
        {
            var bytes = (encoding ?? defaultEncoding).GetBytes(stringData);
            return Deserialize<TData>(bytes);
        }
    }
}