基于非集合的响应的XML反序列化

时间:2015-09-07 20:21:56

标签: c# xml serialization

我使用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类,其中包含time-entry节点的其他属性。然后我写了另一个带有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类中。但我将使用此类进行另一个包含时间总计节点的类的反序列化。

2 个答案:

答案 0 :(得分:0)

查看问题的最佳方法是序列化数据。见下面的代码。查看为xsi生成的两个XML文件: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; }
    }
}
​

答案 1 :(得分:0)

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

方法1:

由于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) };
    }
}

方法2: 通过编写自己的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;
    }
}