将单个XML堆栈反序列化为多个对象

时间:2015-03-24 15:03:36

标签: c# xml serialization xml-deserialization

我正在处理一个返回单个XML块的项目,如下所示:

<root>
  <x_val />
  <x_val2 />
  <x_addr1 />
  <x_addr2 />
  <x_city />
  <x_state />
  <x_country />
  <x_zip />
</root>

在这个项目中,我可以进行多次返回各种信息的调用,但大部分都会在底部包含地址信息。

编写C#类时,我不想在我创建的每个响应对象中为每个节点创建属性。相反,我更喜欢定义一个Address对象,以便这样使用:

[XmlRoot("root")]
[Serializable]
public class ReturnItem1
{
    [XmlElement("x_val")]
    public string FirstValue{ get; set; }

    [XmlElement("x_val2")]
    public string SecondValue{ get; set; }

    public Address AddressInfo { get; set; }

    public ReturnItem1()
    {
        AddressInfo = new Address();
    }
}

public class Address
{
    [XmlElement("x_addr1")]
    public string Address1 { get; set; }

    [XmlElement("x_addr2")]
    public string Address2 { get; set; }

    [XmlElement("x_city")]
    public string City { get; set; }

    [XmlElement("x_state")]
    public string State { get; set; }

    [XmlElement("x_country")]
    public string Country { get; set; }

    [XmlElement("x_zip")]
    public string PostalCode { get; set; }
}

反序列化时,我执行以下逻辑(响应类型为XElement):

var serializer = new XmlSerializer(typeof(ReturnItem1));
var returnObject = (ReturnItem1)serializer.Deserialize(response.CreateReader());

FirstValue和SecondValue的值填充在returnObject中,但Address中的属性始终为null。

我尝试将[XmlRoot(&#34; root)&#34;]属性添加到Address类中,但这并不起作用。也没有将ReturnItem1中Address属性的XmlElement属性设置为&#34; root&#34;或任何其他节点名称。

有没有办法使用这种方法将单个XML节点反序列化为具有一个或多个子对象的对象?

2 个答案:

答案 0 :(得分:0)

尝试使用与XML元素匹配的私有成员和封装它们的公共地址属性。见这个例子:

https://msdn.microsoft.com/en-us/library/6exf3h2k%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-3

答案 1 :(得分:0)

我已经设法使用TAMTAM的建议将XML反序列化为对象,如下所示:

[DataContract(Name="root", Namespace = "")]
public class ReturnItem1
{
    [DataMember(Name = "x_val", Order = 0)]
    public string FirstValue { get; set; }

    [DataMember(Name = "x_val2", Order = 1)]
    public string SecondValue { get; set; }

    [DataMember(Name = "x_addr1", Order = 2)]
    private string _address;

    [DataMember(Name = "x_addr2", Order = 3)]
    private string _address2;

    [DataMember(Name = "x_city", Order = 4)]
    private string _city;

    [DataMember(Name = "x_state", Order = 5)]
    private string _state;

    [DataMember(Name = "x_country", Order = 6)]
    private string _country;

    [DataMember(Name = "x_zip", Order = 7)]
    private string _postalCode;

    public Address AddressInfo { get; set; }

    [OnDeserialized()]
    void OnDeserialized(StreamingContext context)
    {
        AddressInfo = new Address
        {
            Address1 = _address,
            Address2 = _address2,
            PostalCode = _postalCode,
            City = _city,
            Country = _country,
            State = _state
        };
    }
}

我终于找到了一个可以忍受的解决方案。 ReturnItem1扩展了一个包含List of AdditionalAttributesToDeserialize的基类。然后在ReturnItem1的OnDeserialized方法中,我添加&#34; AddressInfo&#34;到那个清单。在反序列化基础对象之后,我迭代遍历该列表,使用Reflection查找属性和属性的类型,并且对于每个条目,程序创建新的DataContractSerializer并在使用Reflection设置属性之前反序列化属性&# 39; s对新反序列化对象的值。它是一种蛮力方法,在将属性名称添加到AdditionalPropertiesToDeserialize列表时很容易指责属性名称,但它允许我在一个地方定义我的对象和属性并随意重用它们。