【问题标题】:XML Deserialization For Non-Collection Based Responses非基于集合的响应的 XML 反序列化
【发布时间】:2015-09-07 20:21:55
【问题描述】:

我正在使用 API 来获取有关 Web 应用程序的一些信息。我编写了类来反序列化 XML 响应并添加了 XMLRoot、XMLElement 属性。对于带有子项集合的 XML 响应,我可以使用属性进行反序列化。例如

<?xml version="1.0" encoding="UTF-8"?>
<time-entries>
   <time-entry>
        //Other sub nodes
   </time-entry>
   <time-entry>
        //Other sub nodes
   </time-entry>
</time-entries>

对于像上面这样的 XML 响应,我编写了一个 TimeEntry 类,其中包含时间入口节点的其他属性的属性。然后我用下面的 TimeEntry 类集合编写了另一个类

[XmlRoot("time-entries")]
public class TimeEntryResponse
{
    public TimeEntryResponse()
    {

    }

    [XmlElement("time-entry")]
    public List<TimeEntry> TimeEntries { get; set; }

}

因此,使用 TimeEntryResponse 类,我可以反序列化 XML 响应,例如问题的顶部。

但我不能像下面的响应那样反序列化。

<?xml version="1.0" encoding="UTF-8"?>
<time-totals>
   <total-mins-sum type="integer">382743</total-mins-sum>
   <non-billed-mins-sum type="integer">328988</non-billed-mins-sum>
   <non-billable-hours-sum type="integer">3137.30</non-billable-hours-sum>
</time-totals>

我还为此响应编写了 TimeTotal 类。

[XmlRoot("time-totals")]
public class TimeTotal
{
    [XmlElement("total-mins-sum")]
    public double TotalMinsSum { get; set; }
    [XmlElement("non-billed-mins-sum")]
    public double NonBilledMinsSum { get; set; }
    [XmlElement("non-billable-hours-sum")]
    public double NonBillableHoursSum { get; set; }
}

然后我写了一个响应类。

public class TimeTotalsResponse : IEntityResponse
{
    public TimeTotalsResponse()
    {

    }

    public TimeTotal TimeTotal { get; set; }
}

如您所见,没有此响应的集合,我不知道应该添加响应类 TimeTotal 的哪些属性。

也许我可以将 TimeTotal 类的属性直接放入 TimeTotalResponse 类。但我将使用这个类来反序列化包含 time-totals 节点的类。

【问题讨论】:

  • 为什么不直接反序列化到TimeTotal 类?它应该可以工作。或者如果你还需要实现IEntityResponseTimeTotalsResponse 子类TimeTotal 而不是封装它。
  • @dbc 我不想序列化 TimeTotal 类。我需要返回一个从 IEntityResponse 派生的类,因为我在这个接口上使用泛型方法做了很多工作。如果你在评论中有不同的意思,你能用代码告诉它吗?

标签: c# xml serialization


【解决方案1】:

我认为您不能使用开箱即用的 XmlSerialization 来做到这一点,因为您的对象不会直接映射到 XML。我可以想到两种方法。

方法一:

由于 XML 可以直接反序列化为 TimeTotal,因此首先使用简单的静态方法序列化为 TimeTotal,并将其设置为新创建的 TimeTotalsResponse 的属性,例如:

static void Main(string[] args)
{
     var response = GetResponse(File.ReadAllText("XMLFile1.xml"));
}

static TimeTotalsResponse GetResponse(string xml)
{
    using (StringReader reader = new StringReader(xml))
    {
        var ser = new XmlSerializer(typeof(TimeTotal));
        return new TimeTotalsResponse() { TimeTotal = (TimeTotal)ser.Deserialize(reader) };
    }
}

方法二: 通过编写自己的 XmlSerializer 来自定义序列化,例如:

public class TimeTotalsResponseSerializer : IXmlSerializable
{
    public TimeTotalsResponse Response { get; set; }

    public void ReadXml(XmlReader reader)
    {
        Response = new TimeTotalsResponse();
        Response.TimeTotal = new TimeTotal();

        reader.ReadToDescendant("total-mins-sum");
        Response.TimeTotal.TotalMinsSum = reader.ReadElementContentAsDouble();
        Response.TimeTotal.NonBilledMinsSum = reader.ReadElementContentAsDouble();
        Response.TimeTotal.NonBillableHoursSum = reader.ReadElementContentAsDouble();
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void WriteXml(XmlWriter writer)
    {
    }
}

用法是;

static void Main(string[] args)
{
    XmlReaderSettings settings = new XmlReaderSettings()
    {
        IgnoreWhitespace = true
    };

    string xml = File.ReadAllText("XMLFile1.xml");
    using (XmlReader reader = XmlReader.Create(new StringReader(xml), settings))
    {
        var ser = new TimeTotalsResponseSerializer();
        ser.ReadXml(reader);
        var response = ser.Response;
    }
}

【讨论】:

    【解决方案2】:

    查看问题的最佳方法是对数据进行序列化。请参阅下面的代码。查看为以下内容生成的两个 XML 文件:xsi:type="TimeEntries" 和 xsi:type="TimeTotalsResponse"

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    using System.IO;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME1 = @"c:\temp\test1.xml";
            const string FILENAME2 = @"c:\temp\test2.xml";
            static void Main(string[] args)
            {
                TimeEntries timeEntries = new TimeEntries()
                {
                    timeEntry = new List<TimeEntry>() {
                        new TimeEntry() {},
                        new TimeEntry() {},
                        new TimeEntry() {}
                    }
                };
                TimeTotalsResponse timeTotals = new TimeTotalsResponse()
                {
                    TotalMinsSum = new TypeInteger() { _type = "integer", _value = 382743 },
                    NonBilledMinsSum = new TypeInteger() { _type = "integer", _value = 328988 },
                    NonBillableHoursSum = new TypeInteger() { _type = "integer", _value = 3137.30 }
                };
    
                XmlSerializer serializer = new XmlSerializer(typeof(TimeEntryResponse));
    
                StreamWriter writer = new StreamWriter(FILENAME1);
                serializer.Serialize(writer, timeEntries);
                writer.Flush();
                writer.Close();
                writer.Dispose();
    
                writer = new StreamWriter(FILENAME2);
                serializer.Serialize(writer, timeTotals);
                writer.Flush();
                writer.Close();
                writer.Dispose();
    
    
            }
        }
        [XmlInclude(typeof(TimeEntries))]
        [XmlInclude(typeof(TimeTotalsResponse))]
        [Serializable]
        public class TimeEntryResponse
        {
    
        }
        [XmlRoot("time-entries")]
        public class TimeEntries : TimeEntryResponse
        {
            [XmlElement("time-entry")]
            public List<TimeEntry> timeEntry { get; set; }
        }
        [XmlRoot("time-entry")]
        public class TimeEntry
        {
        }
        [XmlRoot("time-totals")]
        public class TimeTotalsResponse : TimeEntryResponse
        {
    
            [XmlElement("total-mins-sum")]
            public TypeInteger  TotalMinsSum { get; set; }
            [XmlElement("non-billed-mins-sum")]
            public TypeInteger NonBilledMinsSum { get; set; }
            [XmlElement("non-billable-hours-sum")]
            public TypeInteger NonBillableHoursSum { get; set; }
        }
        public class TypeInteger
        {
            [XmlAttribute("type")]
            public string _type { get; set; }
            [XmlText]
            public double _value { get; set; }
        }
    }
    ​
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-30
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多