views:

40

answers:

1

I have a fairly simple DAL assembly that consists of an SalesEnquiry Class which contains a List<T> of another Vehicle class.

We'll be receiving XML files by email that I'm wanting to use to populate instances of my SalesEnquiry class, so I'm trying to use de-serialization.

I've added XMLRoot/XMLElement/XMLIgnore attributes to both classes as I think is appropriate. However, when I try de-serializing, the parent SalesEnquiry object is populated but no child Vehicle objects.

I understand that de-serializing List<T> can be tricky, but I'm not sure why, how to avoid problems, or even if this is why I'm struggling.

While debugging, I've successfully serialized a Vehicle object on it's own, so I'm assuming that I'm heading in the right direction, but when I de-serialize the SalesEnquiry XML (which contains one or more child Vehicles), the List<Vehicle> isn't populated.

Where am I going wrong?

Update:

In a test project, I serialized an SalesEnquiry containing two vehicles and save to a file. I then loaded the file up an de-serialized it back into a different SalesEnquiry object. It worked!

So what was the difference? The vehicles were recorded as follows:

<?xml version="1.0" encoding="utf-8"?>
<enquiry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <enquiry_no>100001</enquiry_no>
  <vehicles>
    <Vehicle>
      <vehicle_type>Car</vehicle_type>
      <vehicle_make>Ford</vehicle_make>
      <vehicle_model>C-Max</vehicle_model>
...

The thing to note is that Vehicle has a an initial capital, whereas my incoming XML doesn't. In my Vehicle class, I gave the class an [XmlRoot("vehicle")] attribute, which I though would make the link, but clearly it doesn't. This makes sense, I guess, because although Vehicle is a class in it's own right, it's merely an array item within a List inside my SalesEnquiry.

In which case, the question is - How do I annotate the Vehicle class such that I can map the incoming XML elements (<vehicle>) to my list items (Vehicle)? [XmlArrayItem] (or [XmlElement] for that matter) are 'not valid on this declaration type'.

In this example, I can request that the people who generate the XML use <Vehicle> rather than <vehicle>, but there may be situations where I don't have this freedom, so I'd rather learn a solution than apply a workaround.


Conclusion:

By adding [XmlArrayItem("vehicle", typeof(Vehicle))] to the existing decoration for my List, the XML is now able to de-serialize fully. Phew!

+2  A: 

Here's a working pair of classes with appropriate decorations:

(Note: The XmlAnyElement and XmlAnyAttribute are optional. It's a habit I'm in to promote the flexibility of the entity.)

[XmlType("enquiry")]
[XmlRoot("enquiry")]
public class Enquiry
{
    private List<Vehicle> vehicles = new List<Vehicle>();

    [XmlElement("enquiry_no")]
    public int EnquiryNumber { get; set; }

    [XmlArray("vehicles")]
    [XmlArrayItem("Vehicle", typeof(Vehicle))]
    public List<Vehicle> Vehicles
    {
        get { return this.vehicles; }
        set { this.vehicles = value ?? new List<Vehicle>(); }
    }

    [XmlAnyElement]
    public XmlElement[] AnyElements;
    [XmlAnyAttribute]
    public XmlAttribute[] AnyAttributes;
}

public class Vehicle
{
    [XmlElement("vehicle_type")]
    public string VehicleType { get; set; }
    [XmlElement("vehicle_make")]
    public string VehicleMake { get; set; }
    [XmlElement("vehicle_model")]
    public string VehicleModel { get; set; }
}
kbrimington
You deserve the 25 reputation for the answer alone, but I wish I could give you more for the thoroughness of this example. Thanks.
CJM
@CJM: I'm just glad to help. Good luck!
kbrimington