sean
sean

Reputation: 11624

XmlSerializer serializing sub objects

How do you serialize the following

[XmlRoot("response")]
public class MyCollection<T>
{
    [XmlElement("person", Type = typeof(Person))]
    public List<T> entry;
    public int startIndex;
}

where T can be a class like

public class Person
{
    public string name;
}

into

<response>
  <startIndex>1</startIndex>
  <entry>
      <person>
         <name>meeee</name>
      </person>
  </entry>
  <entry>
      <person>
         <name>youuu</name>
      </person>
  </entry>
</response>

I have been playing with [XmlArray], [XmlArrayItem], and [XmlElement] and I can't seem to get the right combination. Arrrgghhh.

Update:

[XmlArray("entry")]
[XmlArrayItem("person", Type = typeof(Person))]
public List<T> entry;

gives me

<entry><person></person><person></person></entry>


[XmlElement("person", Type = typeof(Person))]
public List<T> entry;

gives me

<person></person><person></person>

Upvotes: 3

Views: 6120

Answers (3)

sean
sean

Reputation: 11624

I've found a way to do this without using IXmlSerializable. Use the XmlDictionaryWriter for formatting necessary parts and for the rest just stick with the DataContractSerializer. I created an interface for MyCollection

public interface IMyCollection
{
    int getStartIndex();
    IList getEntry();
}

Therefore, MyCollection is no longer decorated with any XMLxxxx attributes. And the method to convert to string is as follows. Can it be improved?

public string ConvertToXML(object obj)
{
    MemoryStream ms = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(ms, Encoding.UTF8, true))
    {
         writer.WriteStartDocument();
         if (obj is IMyCollection)
         {
              IMyCollection collection = (IMyCollection)obj;
              writer.WriteStartElement("response");
              writer.WriteElementString("startIndex","0");
              var responses = collection.getEntry();
              foreach (var item in responses)
              {
                   writer.WriteStartElement("entry");
                   DataContractSerializer ser = new DataContractSerializer(item.GetType());                
                   ser.WriteObject(writer, item);
                   writer.WriteEndElement();
              }
              writer.WriteEndElement();
        }
        writer.Flush();
        return Encoding.UTF8.GetString(ms.ToArray());
}

Upvotes: 1

Rob Cooper
Rob Cooper

Reputation: 28867

This sounds like a similar issue I was having.. I finally cracked it and posted everything on the question here..

XML Serialization and Inherited Types

Is that of any use?

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062745

I can't see any obvious way of getting it to output those results without changing the classes radically... this might not be what you want, but by mirroring the desired output (not uncommon in DTOs) it gets the right result...

Otherwise, you might be looking at IXmlSerializable, which is a huge pain:

using System;
using System.Collections.Generic;
using System.Xml.Serialization;
[XmlRoot("response")]
public class MyResponse {
    public MyResponse() {
        Entries = new List<Entry>();
    }
    [XmlElement("startIndex", Order = 1)]
    public int StartIndex { get; set; }
    [XmlElement("entry", Order = 2)]
    public List<Entry> Entries { get; set; }
}
public class Entry {
    public Entry() { }
    public Entry(Person person) { Person = person; }
    [XmlElement("person")]
    public Person Person { get; set; }
    public static implicit operator Entry(Person person) {
        return person == null ? null : new Entry(person);
    }
    public static implicit operator Person(Entry entry) {
        return entry == null ? null : entry.Person;
    }
}
public class Person {
    [XmlElement("name")]
    public string Name { get; set; }
}
static class Program {
    static void Main() {
        MyResponse resp = new MyResponse();
        resp.StartIndex = 1;
        resp.Entries.Add(new Person { Name = "meeee" });
        resp.Entries.Add(new Person { Name = "youuu" });
        XmlSerializer ser = new XmlSerializer(resp.GetType());
        ser.Serialize(Console.Out, resp);
    }
}

Upvotes: 4

Related Questions