【问题标题】:How to create a class to XML Serializer如何为 XML Serializer 创建一个类
【发布时间】:2009-10-01 04:13:10
【问题描述】:

我的xml格式如下:

<FavouriteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Customer>
    <ID>12</ID>
    <ID>2</ID>
    <ID>5</ID>
  </Customer>

  <Supplier>
    <ID>158</ID>
    <ID>23</ID>
    <ID>598</ID>
  </Supplier>
</FavouriteSettings>

================================================ ===============
我会有一个像下面这样的课程

class FavouriteList
{
   public string Name; // this name will be "Customer" and "Supplier"
   public List<int> aList; // to store those "ID" value
}

Class FavouriteSettings
{
   public List<FavouriteList> bigList;
}

我需要做什么或改变才能使此类与 XMLSerializer 一起使用以生成类似该格式的 XML 文件并反序列化回列表和类作为 FavouriteList?

【问题讨论】:

  • (添加了第二个示例,显示 LINQ-to-XML 与您现有的类型)

标签: c# .net xml xml-serialization


【解决方案1】:

XmlSerializer 旨在将您的对象非常直接地转换为 xml;你可以使用IXmlSerializable,但这很少值得。您最好创建反映 xml 结构的对象。或者,更简单 - 使用 xsd 为您完成:

xsd example.xml
xsd example.xsd /classes

或者我怀疑以下方法会起作用(未经测试)

using System.Collections.Generic;
using System.Xml.Serialization;
public class FavoriteSettings
{
    [XmlArray("Customer")]
    [XmlArrayItem("ID")]
    public List<int> Customers { get; set; }

    [XmlArray("Supplier")]
    [XmlArrayItem("ID")]
    public List<int> Suppliers { get; set; }
}

特别是;如果您希望 元素 名称(“客户”等)根据数据(“名称”等)而变化 - 那么除非您使用 IXmlSerializable 或自己编写,否则它不会发生与XDocument(或类似)。对于这样的简单数据,也许XDocument 是一个可行的选择?但是你会做很多额外的工作,尤其是在反序列化期间。


这是一个通过 LINQ-to-XML 使用 现有 类的示例:

static class Program
{
    static void Main() {
        var favs = new FavouriteSettings
        {
            bigList = new List<FavouriteList>
            {
                new FavouriteList {
                    Name = "Customer",
                    aList = new List<int>{
                        12,2,5
                    }
                }, new FavouriteList {
                    Name = "Supplier",
                    aList = new List<int>{
                        158, 23, 598
                    }
                }
            }
        };
        var el = new XElement("FavoriteSettings",
            from fav in favs.bigList
            select new XElement(fav.Name,
                from item in fav.aList
                select new XElement("ID", item)));

        string xml = el.ToString();
        Console.WriteLine(xml);

        el = XElement.Parse(xml);
        favs = new FavouriteSettings
        {
            bigList = new List<FavouriteList>(
                from outer in el.Elements()
                select new FavouriteList
                {
                    Name = outer.Name.LocalName,
                    aList = new List<int>(
                        from id in outer.Elements("ID")
                        select (int)id
                    )
                })
        };
    }
}

【讨论】:

  • 如果您愿意添加一些仅供 XmlSerializer 使用的公共成员,实际上可以破解 XmlSerializer 来执行此操作 - 请参阅我的答案。不过还是很丑。
【解决方案2】:

您可以使用以下类以及 XmlSerializer 来序列化/反序列化到/从所需的 XML:

  public class FavouriteSettings
  {
    public ID[] Customer
    {
      get;
      set;
    }

    public ID[] Supplier
    {
      get;
      set;
    }
  }

  public class ID
  {
    [XmlText()]
    public int Value
    {
      get;
      set;
    }
  }

【讨论】:

    【解决方案3】:

    如果您必须在类定义中保留所有现有名称,并且为 Customer 和 Supplier 引入类层次结构是不可能的,那么您将需要这样的 hack:

    public class FavouriteList
    {
       [XmlIgnore]
       public string Name; // this name will be "Customer" and "Supplier"
    
       [XmlElement("ID")]
       public List<int> aList; // to store those "ID" value
    }
    
    public class FavouriteSettings
    {
       [XmlIgnore]
       public List<FavouriteList> bigList;
    
       [XmlElement("Customer")]
       public FavouriteList[] Customers
       {
           get { return bigList.Where(fl => fl.Name == "Customer").ToArray(); }
           set { bigList.AddRange(value); }
       }
    
       [XmlElement("Supplier")]
       public FavouriteList[] Suppliers
       {
           get { return bigList.Where(fl => fl.Name == "Supplier").ToArray(); }
           set { bigList.AddRange(value); }
       }
    }
    

    【讨论】:

    • 回复您的评论;我想这取决于“客户”/“供应商”是固定的还是动态的——即基于数据。
    • 你的意思是,“类型”列表是在编译时固定的,还是在运行时可扩展的?
    • 我想我每天都在学习新东西......因为我只是一个新的 Linq。谢谢PM
    【解决方案4】:

    XMLSerializer(常规的)喜欢做自己的事情,结果往往很丑陋。你可以通过实现 IXmlSerializable 来半控制序列化,但是如果你有类似“List”的东西,.NET 会杀掉它。

    我认为您可以改用 DataContractXmlSerializer 获得准确的结果。用 [DataContract] 标记该类,并在要序列化的每个元素上放置一个 [DataMember]。

    【讨论】:

    • DataContractXmlSerializer?有这样的野兽吗? DataContractSerializer,otoh 对于特定的 xml 来说是个糟糕的选择;例如,对属性之类的东西的控制很少。对于xml,使用XmlSerializer,或者使用XDocument等自己编写。
    【解决方案5】:

    我相信您可以使用属性来控制数据的序列化方式。请参阅此 MSDN 文章:“Attributes That Control XML Serialization”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-13
      • 2022-12-13
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多