OK, so here's the story so far.
I could already deserialize individual objects using XmlSerializer
, but deserializing lists was proving to be a real headache. I started out by trying to serialize List<Foo>
and the serializer serialized multiple <Foo>
XML structures inside a root <ArrayOfFoo>
element. That proved to be problematic to deserialize, so it looks like I needed to have defined the 'ArrayOfFoo' element myself. So, I've got a class working that is a 'wrapper' for the list, as shown in this program:
using System;
using System.IO;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace XmlTester2
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("XML tester...");
string xml =
"<ItemList xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<Person i:type=\"PersonI2\">" + "<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" + "</Person>" +
"<Account i:type=\"AccountI2\">" + "<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" + "</Account>" +
"<Person i:type=\"PersonI2\">" + "<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" + "<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" + "</Person>" + "</ItemList>";
XmlSerializer ser = new XmlSerializer(typeof(ItemList));
using (var reader = new StringReader(xml))
{
ItemList result = (ItemList)ser.Deserialize(reader);
}
Console.WriteLine("Break here and check 'result' in Quickwatch...");
Console.ReadKey();
}
}
[XmlRootAttribute(IsNullable = false)]
public class ItemList
{
[XmlElementAttribute("Person")]
public List<Person> Persons { get; set; }
[XmlElementAttribute("Account")]
public List<Account> Accounts { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "Person", Namespace = "")]
[XmlInclude(typeof(PersonI2))]
public class Person
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "PersonI2", Namespace = "")]
public class PersonI2 : Person
{
public string Field4 { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "Account", Namespace = "")]
[XmlInclude(typeof(AccountI2))]
public class Account
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "AccountI2", Namespace = "")]
public class AccountI2 : Account
{
public string Field4 { get; set; }
}
}
However, this 'wrapper', ItemList
, still has to have manually defined in it all the elements that might be contained (in the example, Person and Account). What would be really ideal would be to have a generic list wrapper class. I know this is a bit hopeful, but would there be a way to do this? I'm thinking of something along these lines (this does not work, but is just to give you the general idea):
using System;
using System.IO;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace XmlTester3
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("XML tester...");
string xml =
"<ItemList xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<Person i:type=\"PersonI2\">" +
"<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" +
"<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" +
"</Person>" +
"<Person i:type=\"PersonI2\">" +
"<Field1>field1Val</Field1>" +
"<Field2>field2Val</Field2>" +
"<Field3>field3Val</Field3>" +
"<Field4>field4Val</Field4>" +
"</Person>" +
"</ItemList>";
XmlSerializer ser = new XmlSerializer(typeof(ItemList<Person>));
using (var reader = new StringReader(xml))
{
ItemList<Person> result = (ItemList<Person>)ser.Deserialize(reader);
}
Console.WriteLine("Break here and check 'result' in Quickwatch...");
Console.ReadKey();
}
}
[XmlRootAttribute(IsNullable = false)]
[XmlInclude(typeof(Person))]
[XmlInclude(typeof(PersonI2))]
[XmlInclude(typeof(Account))]
[XmlInclude(typeof(AccountI2))]
public class ItemList<T>
{
[XmlElementAttribute]
public List<T> Items { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "Person", Namespace = "")]
[XmlInclude(typeof(PersonI2))]
public class Person
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "PersonI2", Namespace = "")]
public class PersonI2 : Person
{
public string Field4 { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "Account", Namespace = "")]
[XmlInclude(typeof(AccountI2))]
public class Account
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
[XmlTypeAttribute(AnonymousType = false, TypeName = "AccountI2", Namespace = "")]
public class AccountI2 : Account
{
public string Field4 { get; set; }
}
}
So, the XML structures passed inside the ItemList
would only be able to be of one type, say Person
in this example, and I could define an ItemList<Person>
that would allow me to deserialize a list containing multiple Person objects? Any ideas? If necessary, I wouldn't mind having to tag the ItemList
class with an [XmlInclude...]
for every type that ItemList
might contain a collection of.
I'm guessing this is possible, I just haven't figured out quite how? :-) Or is the default XmlSerializer too fussy?