Search code examples
c#xmlxml-deserialization

Unable to deserialize an XML string


I have the following xml which I'm trying to deserialize as follows but I get error:

There was an error reflecting type 'System.Collections.Generic.List`1[MyApp.Models.Field]

Below is my code

public class FieldList
{
    [XmlArray("fields")]
    [XmlArrayItem("field")]
    List<Field> Fields { get; set; }
}

public class Field
{
    [XmlAttribute("type")]
    public string Type { get; set; }

    [XmlAttribute("required")]
    public bool Required { get; set; }

    [XmlAttribute("label")]
    public string Label { get; set; }

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

    [XmlElement("option")]
    [JsonProperty("values")]
    public List<Option> Options { get; set; }
}

public class Option
{
    [XmlAttribute("label")]
    public string Label { get; set; }

    [XmlAttribute("value")]
    public string Value { get; set; }

    [XmlAttribute("selected")]
    public bool Selected { get; set; }

    /// <remarks/>
    [XmlIgnore()]
    public bool SelectedSpecified { get; set; }

    [XmlText]
    public string Text { get; set; }
}

var xml =  @"<?xml version=""1.0"" ?>
   <form-template>
    <fields>
        <field type=""select"" required=""true"" label=""Cars"" name=""cars"" >
            <option label=""Toyota"" value=""Toyota"" selected=""true"">Toyota</option>
            <option label=""Nisan"" value=""Nisan"" >Nisan</option>
        </field>
    </fields>
   </form-template>";


 var serializer = new XmlSerializer(typeof(FieldList), new XmlRootAttribute("form-template"));
 var stringReader = new StringReader(xml);
 var xmlFields = (FieldList)serializer.Deserialize(stringReader);

What am I doing wrong?

* UPDATE *

As per comments below changing

 public IEnumerable<Option> Options { get; set; }

To

  public List<Option> Options { get; set; }

fixes the error but now nothing is deserialized - the variable xmlFields is empty??? Do I need to read from a particular node or should it not matter?


Solution

  • Let's look at your code.

    new XmlRootAttribute("form-template") maps to <form-template> node.

    public class Field maps to <field node.

    But nothing maps to <fields> node.

    Add following class:

    public class FieldList
    {
        [XmlArray("fields")]
        [XmlArrayItem("field")]
        public List<Field> Fields { get; set; }
    }
    

    It should work:

    var serializer = new XmlSerializer(typeof(FieldList), new XmlRootAttribute("form-template"));
    var stringReader = new StringReader(xml);
    var xmlFields = (FieldList)serializer.Deserialize(stringReader);
    

    Also, you should add a property to the Option class:

    [XmlText]
    public string Text { get; set; }
    

    Update.

    You can get rid of the FieldList class. But then you have to manually skip part of xml nodes.

    List<Field> xmlFields;
    var serializer = new XmlSerializer(typeof(List<Field>), new XmlRootAttribute("fields"));
    
    // You can read from a stream or from a StringReader instead of a file
    using (var xmlReader = XmlReader.Create("test.xml"))
    {
        // Skip <form-template> node
        xmlReader.ReadToFollowing("fields");
    
        xmlFields = (List<Field>)serializer.Deserialize(xmlReader);
    }
    

    Add XmlType attribute to your class:

    [XmlType("field")]
    public class Field