Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Set XmlArrayItem Element name for a List<Custom> implementation?

I want to create a custom XML structure as follows:

<Hotels>
    <Hotel />
</Hotels>

I've created an implementation of List just to be able to do this. My code is as follows:

[XmlRootAttribute(ElementName="Hotels")]
public class HotelList: List<HotelBasic>

Because the class that List holds is not named Hotel but HotelBasic my xml is like

<Hotels>
   <HotelBasic />
</Hotels>

How do I fix this without having to implement ISerializable or IEnumerable?

like image 615
Odys Avatar asked Nov 24 '11 08:11

Odys


3 Answers

[XmlArray("Hotels")]
[XmlArrayItem(typeof(Hotel), ElementName="Hotel")]
public HotelList[] Messages { get; set; }

should produce:

<Hotels>
    <Hotel />
    <Hotel />
</Hotels>

[XmlRoot("Hotels")]
public class HotelList : IXmlSerializable
{
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        this.Hotels = XDocument.Load(reader)
                               .Select(h => new Hotel { Name = (string)h.Attribute("name") }
                               .ToList();
    }

    public void WriteXml(XmlWriter writer)
    {
        throw new NotSupportedException();
    }
}
like image 60
abatishchev Avatar answered Nov 18 '22 12:11

abatishchev


Assuming you are using XmlSerializer, if all you want to do is change how your HotelBasic class is serialized, you can use XmlTypeAttribute:

[XmlType(TypeName = "Hotel")]
public class HotelBasic
{
    public string Name { get; set; }
}

When used with your HotelList class it will be serialized as:

<Hotels xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Hotel>
    <Name>One</Name>
  </Hotel>
  <Hotel>
    <Name>Two</Name>
  </Hotel>
</Hotels>
like image 30
madd0 Avatar answered Nov 18 '22 13:11

madd0


I think madd0 shows the simplest option for you here, but just for completeness... personally I don't recommend the "serialize the list as the root object" - for various reasons (including: I've seen those attributes not work on at least on platform - might have been CF or SL, can't remember). Instead, I always advise using a custom root type:

[XmlRoot("Hotels")]
public class HotelResult // or something similar
{
    [XmlElement("Hotel")]
    public List<HotelBasic> Hotels { get { return hotel; } }

    private readonly List<HotelBasic> hotels = new List<HotelBasic>();
}

This will have the same xml structure, and allows greater flexibility (you can add other attributes / elements to the root), and doesn't bake List<T> into your type model (prefer encapsulation over inheritance, etc).

like image 8
Marc Gravell Avatar answered Nov 18 '22 13:11

Marc Gravell