Scott Scott - 1 month ago 7
C# Question

Deserialize list within list item

I have the following sample XML that I was given. I need to deserialize it.

<?xml version="1.0" encoding="utf-16"?>
<Users filename="testfile">
<User name="John Doe" age="51">
<Addresses>
<Address street="1511 Smith Pl." city="Boulder" state="CO" zip="80000" />
<Address street="1820 Main St." city="Lafayette" state="CO" zip="80100" />
</Addresses>
</User>
<User name="Jeff Jones" age="35">
<Addresses>
<Address street="2111 Jefferson Rd.." city="Colorado Springs" state="CO" zip="80099" />
</Addresses>
</User>
</Users>


I am using the following code:

private void button1_Click(object sender, EventArgs e)
{
XmlSerializer xmlIn = new XmlSerializer(typeof(UserItems));
StreamReader srIn = new StreamReader("c:\\address.xml");
UserItems uiItems;

uiItems = (UserItems)xmlIn.Deserialize(srIn);

srIn.Close();
}
}

[XmlRoot("Users")]
public class UserItems
{
private List<UserItem> p_liUserItems;

[XmlAttribute("filename")] public string FileName { get; set; }

[XmlElement("User")]
public List<UserItem> Users
{
get
{
return p_liUserItems;
}
set
{
p_liUserItems = value;
}
}
}

[Serializable]
public class UserItem
{
private List<AddressItem> p_liAddressItems = new List<AddressItem>();

[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("age")]
public string Age { get; set; }

[XmlElement("Address")]
public List<AddressItem> Addresses
{
get
{
return p_liAddressItems;
}
set
{
p_liAddressItems = value;
}
}
}

[Serializable]
public class AddressItem
{
[XmlAttribute("street")]
public string Street { get; set; }
[XmlAttribute("city")]
public string City { get; set; }
[XmlAttribute("state")]
public string State { get; set; }
[XmlAttribute("zip")]
public string ZipCode { get; set; }
}


This deserializes fine, up to a point. I get the information for each of the users, but I am not getting any of the addresses for each user. Each user has a blank addresses list How does one go about deserializing collections within collection items?

Answer

Your Addresses is an XmlElement, but one that wraps an array. You can (de)serialize it using XmlArray and XmlArrayItem to prevent having to create and decorate a wrapper class for Addresses:

[XmlArray("Addresses")]
[XmlArrayItem("Address")]
public List<AddressItem> Addresses
{
    get
    {
        return p_liAddressItems;
    }
    set
    {
        p_liAddressItems = value;
    }
}

Alternatively, if you do want the wrapper class:

[Serializable]
public class UserItem
{
    [XmlAttribute("name")]
    public string Name { get; set; }
    [XmlAttribute("age")]
    public string Age { get; set; }

    [XmlElement("Addresses")]
    public AddressWrapper Addresses { get; set; }
}

[Serializable]
public class AddressWrapper
{
    [XmlElement("Address")]
    public List<AddressItem> Addresses { get; set; }
}

See also Wrapping Serialized Array Elements with the Name of the Array.