Search code examples
c#xmldeserializationxml-serialization

deserializing a string which has more nodes then type that will be returned in c#


I have an XML string which is retrieved as an xml string from API call. I need to convert this into view model in my application so that this can be displayed in the view. however as the viewmodel only has few nodes/elements as there are in the xml document I get an exception thrown when I try to deserialize it. below is the code and the error.

API End Point returns this

<response>
  <data>
    <categories>
      <category>
        <id>1</id>
        <name>hats</name>
      </category>
    </categories>
  </data>
</response>

Code:

namespace CatApp.Models
{
[XmlRoot("Categories")]
public class CategoriesViewModel
{
    public CategoriesViewModel()
    {
        _categories = new List<Category>();
    }


    private  List<Category> _categories;
    [XmlElement("Category")]
    public List<Category> Categories
    {
        get { return _categories; }
        set { value = _categories; }
    }

    public class Category
    {
        [XmlElement("Id")]
        public int Id { get; set; }

        [XmlElement("Name")]
        public string Name { get; set; }
    }

  }
}


  public static async Task<CategoriesViewModel> GetAllCategories()
  {
        var model = new CategoriesViewModel();
        try
        {
            var response = await client.GetStreamAsync(uri);
            model = DeserializeXMLToObject<CategoriesViewModel>(response);


        }
        catch (Exception ex)
        {
            var exception = ex;
        }
        return model;
    }

   public static T DeserializeXMLToObject<T>(Stream stream)
   {
        T returnObject = default(T);
        try
        {
                XmlSerializer serializer = new XmlSerializer(typeof(T));

                returnObject = (T)serializer.Deserialize(stream);
        }
        catch (Exception ex)
         {

        }
        return returnObject;
    }

Error at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
at CatApp.Controllers.HomeController.DeserializeXMLToObject[T](Stream stream) in C:\Users\umerh\source\repos\CatAPI\CatApp\Controllers\HomeController.cs:line 50


Solution

  • First, the element names in the C# attributes must match the element names in the XML. Case sensitive: Categories not equal categories and so on.

    [XmlRoot("categories")] // <--
    public class CategoriesViewModel
    {
        public CategoriesViewModel()
        {
            _categories = new List<Category>();
        }
    
        private List<Category> _categories;
    
        [XmlElement("category")] // <--
        public List<Category> Categories
        {
            get { return _categories; }
            set { value = _categories; }
        }
    
        public class Category
        {
            [XmlElement("id")] // <--
            public int Id { get; set; }
    
            [XmlElement("name")] // <--
            public string Name { get; set; }
        }
    }
    

    Second, you can skip some of the xml elements as follows:

    public static T DeserializeXMLToObject<T>(Stream stream)
    {
        T returnObject = default(T);
        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
    
            using (var xmlReader = XmlReader.Create(stream))
            {
                xmlReader.ReadToFollowing("categories"); // Skip elements before categories node
                returnObject = (T)serializer.Deserialize(xmlReader);
            }
        }
        catch (Exception ex)
        {
    
        }
        return returnObject;
    }