Is it possible to deserialize XML into List<T>?
Solution 1
You can encapsulate the list trivially:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
[XmlRoot("user_list")]
public class UserList
{
public UserList() {Items = new List<User>();}
[XmlElement("user")]
public List<User> Items {get;set;}
}
public class User
{
[XmlElement("id")]
public Int32 Id { get; set; }
[XmlElement("name")]
public String Name { get; set; }
}
static class Program
{
static void Main()
{
XmlSerializer ser= new XmlSerializer(typeof(UserList));
UserList list = new UserList();
list.Items.Add(new User { Id = 1, Name = "abc"});
list.Items.Add(new User { Id = 2, Name = "def"});
list.Items.Add(new User { Id = 3, Name = "ghi"});
ser.Serialize(Console.Out, list);
}
}
Solution 2
If you decorate the User
class with the XmlType
to match the required capitalization:
[XmlType("user")]
public class User
{
...
}
Then the XmlRootAttribute
on the XmlSerializer
ctor can provide the desired root and allow direct reading into List<>:
// e.g. my test to create a file
using (var writer = new FileStream("users.xml", FileMode.Create))
{
XmlSerializer ser = new XmlSerializer(typeof(List<User>),
new XmlRootAttribute("user_list"));
List<User> list = new List<User>();
list.Add(new User { Id = 1, Name = "Joe" });
list.Add(new User { Id = 2, Name = "John" });
list.Add(new User { Id = 3, Name = "June" });
ser.Serialize(writer, list);
}
...
// read file
List<User> users;
using (var reader = new StreamReader("users.xml"))
{
XmlSerializer deserializer = new XmlSerializer(typeof(List<User>),
new XmlRootAttribute("user_list"));
users = (List<User>)deserializer.Deserialize(reader);
}
Credit: based on answer from YK1.
Solution 3
I think I have found a better way. You don't have to put attributes into your classes. I've made two methods for serialization and deserialization which take generic list as parameter.
Take a look (it works for me):
private void SerializeParams<T>(XDocument doc, List<T> paramList)
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(paramList.GetType());
System.Xml.XmlWriter writer = doc.CreateWriter();
serializer.Serialize(writer, paramList);
writer.Close();
}
private List<T> DeserializeParams<T>(XDocument doc)
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<T>));
System.Xml.XmlReader reader = doc.CreateReader();
List<T> result = (List<T>)serializer.Deserialize(reader);
reader.Close();
return result;
}
So you can serialize whatever list you want! You don't need to specify the list type every time.
List<AssemblyBO> list = new List<AssemblyBO>();
list.Add(new AssemblyBO());
list.Add(new AssemblyBO() { DisplayName = "Try", Identifier = "243242" });
XDocument doc = new XDocument();
SerializeParams<T>(doc, list);
List<AssemblyBO> newList = DeserializeParams<AssemblyBO>(doc);
Solution 4
Yes, it will serialize and deserialize a List<>. Just make sure you use the [XmlArray] attribute if in doubt.
[Serializable]
public class A
{
[XmlArray]
public List<string> strings;
}
This works with both Serialize() and Deserialize().
Solution 5
Yes, it does deserialize to List<>. No need to keep it in an array and wrap/encapsulate it in a list.
public class UserHolder
{
private List<User> users = null;
public UserHolder()
{
}
[XmlElement("user")]
public List<User> Users
{
get { return users; }
set { users = value; }
}
}
Deserializing code,
XmlSerializer xs = new XmlSerializer(typeof(UserHolder));
UserHolder uh = (UserHolder)xs.Deserialize(new StringReader(str));
Related videos on Youtube
Daniel Schaffer
Updated on August 02, 2020Comments
-
Daniel Schaffer almost 4 years
Given the following XML:
<?xml version="1.0"?> <user_list> <user> <id>1</id> <name>Joe</name> </user> <user> <id>2</id> <name>John</name> </user> </user_list>
And the following class:
public class User { [XmlElement("id")] public Int32 Id { get; set; } [XmlElement("name")] public String Name { get; set; } }
Is it possible to use
XmlSerializer
to deserialize the xml into aList<User>
? If so, what type of additional attributes will I need to use, or what additional parameters do I need to use to construct theXmlSerializer
instance?An array (
User[]
) would be acceptable, if a bit less preferable. -
JaredPar over 15 years@Daniel, AFAIK, no. You need to serialize and deserialize into some concrete object type. I do not believe that XML serialization natively supports collection classes as the start of a serialization. I do not 100% know that though.
-
Jon Kragh almost 14 yearsNice solution with the [XmlElement("user")] to avoid an extra level of elements. Looking at this, I thought for sure that it would have emitted a <user> or <Items> node (if you did not have the XmlElement attribute), and then add <user> nodes under that. But I tried it and it did not, thus emitting exactly what the question wanted.
-
Max Toro about 12 yearsThanks for actually answering the question. I would add that for
List<MyClass>
the document element should be namedArrayOfMyClass
. -
Picrofo Software over 11 yearsWelcome to stackoverflow! It's always better to provide a short description for a sample code to improve the post accuracy :)
-
Kala J about 10 yearsWhat if I had two lists under UserList above? I tried your method and it says it already defines a member called XYZ with the same parameter types
-
eduardobr over 8 years[XmlElement("list")] should be [XmlArray("list")] instead. That is the only way Deserialization worked for me in .NET 4.5
-
DDRider62 over 7 yearsIn my point of view, this is clearly THE answer to the question. The question was about deserializing into List<T>. All the other solutions, except maybe one, include a wrapping class to contain the list, which was certainly not the question posted, and what the author of the question seems to be trying to avoid.
-
DDRider62 over 7 yearsI don't know why this is marked as right answer. It includes adding a class to wrap the list. That was certainly what the question is trying to avoid.
-
Marc Gravell over 7 years@DDRider62 the question doesn't say "without wrapping". Most people are pretty pragmatic and just want to get the data out. This answer allows you to do that, via the
.Items
member. -
dbc almost 6 yearsWith this approach, the
XmlSerializer
must be statically cached and reused to avoid a severe memory leak, see Memory Leak using StreamReader and XmlSerializer for details.