Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize XML with Attributes in C#

I'm having trouble deserializing an XML response from an API call. My 'Option' object's property 'Description' is null.

Below is a sample of the XML:

<vehicle found="1">
   <description>VehicleDescText</description>
   <buildDate>2000-11-20</buildDate>
   <modelYear>2001</modelYear>
   <optionList>
      <option code="UH8">OptionDesc1</option>
      <option code="UH8">OptionDesc2</option>
   </optionList>
</vehicle>

Here is a sample of C# classes:

[DataContract]
[XmlRoot("vehicle")]
public class Vehicle
{
    [DataMember]
    [XmlAttribute("found")]
    public bool Found { get; set; }

    [DataMember]
    [XmlElement("description")]
    public string Description { get; set; }

    [DataMember]
    [XmlElement("buildDate")]
    public string BuildDate { get; set; }

    [DataMember]
    [XmlElement("modelYear")]
    public string ModelYear { get; set; }

    [DataMember]
    [XmlElement("optionList")]
    public List<Option> OptionList { get; set; }
}

public class Option
{
    [DataMember]
    [XmlAttribute("code")]
    public string Code { get; set; }

    [DataMember]
    [XmlElement("option")]
    public string Description { get; set; }
}

Deserializing the object looks like this:

var xmlDeserializer = new RestSharp.Deserializers.XmlDeserializer();
results = xmlDeserializer.Deserialize<Vehicle>(response);

Where am I going wrong here? As I would prefer not to modify the underlying data model, what Attributes can I add or modify to fix the problem?

like image 352
TopBanana9000 Avatar asked Dec 03 '25 18:12

TopBanana9000


1 Answers

You have marked your types with XML serializer attributes and data contract attributes, but the deserializer you are using, RestSharp.Deserializers.XmlDeserializer, does not support these attributes.

Instead, as explained in its documentation, it supports the [DeserializeAs] attribute which allows for control of XML node name and element vs. attribute status.

But as noted in @apocalypse's answer as well as this older question there is a special case in the documentation regarding deserialization of element values into property values:

If the XML returned is like this:

<Response>Hello world</Response>

There's no way to directly represent that in a C# class:

public class Response {
}

You need something to hold the value of the Response element. In this case, add a property called Value and it will be populated:

public class Response {
     public string Value { get; set; }
}

This condition is checked for between searching for matching element names and matching attribute names.

I.e. if your rename Description to Value you will be able to deserialize that XML successfully. (Sample fiddle #1.)

However, it appears you do not wish to rename your Description property. If so, you can instead apply [DeserializeAs(Name = "Value")] to it and the special case will again apply:

public class Option
{
    public string Code { get; set; }

    [DeserializeAs(Name = "Value")]
    public string Description { get; set; }
}

Sample fiddle #2.

Finally, as an alternative solution you could switch to RestSharp.Deserializers.DotNetXmlDeserializer and use regular XmlSerializer attributes, specifically [XmlText]. Thus your code would become:

var xmlDeserializer = new RestSharp.Deserializers.DotNetXmlDeserializer();
var results = xmlDeserializer.Deserialize<Vehicle>(response);

And your types would look like:

[XmlRoot("vehicle")]
public class Vehicle
{
    [XmlAttribute("found")]
    public bool Found { get; set; }

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

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

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

    [XmlArray("optionList")]
    [XmlArrayItem("option")]
    public List<Option> OptionList { get; set; }
}

public class Option
{
    [XmlAttribute("code")]
    public string Code { get; set; }

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

Sample fiddle #3.

like image 99
dbc Avatar answered Dec 06 '25 09:12

dbc