Monday, April 11, 2011

Is it possible to deserialize XML into List<T>?

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 a List<User> ? If so, what type of additional attributes will I need to use, or what additional parameters do I need to use to construct the XmlSerializer instance?

EDIT: An array ( User[] ) would be acceptable, if a bit less preferable as well.

From stackoverflow
  • Not sure about List<T> but Arrays are certainly do-able. And a little bit of magic makes it really easy to get to a List again.

    public class UserHolder {
       [XmlElement("list")]
       public User[] Users { get; set; }
    
       [XmlIgnore]
       public List<User> UserList { get { return new List<User>(Users); } }
    }
    
    Daniel Schaffer : Is it possible to do without the "holder" class?
    JaredPar : @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.
  • 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().

  • 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);
        }
    }
    
    Jon Kragh : Nice 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 or node (if you did not have the XmlElement attribute), and then add nodes under that. But I tried it and it did not, thus emitting exactly what the question wanted.
  • 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)xSerializer.Deserialize(new StringReader(str));
    

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.