0

I have a XML that looks like this that I need to deserialize:

<?xml version="1.0" encoding="utf-8" ?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Countries>
      <Country>
        <CountryCode>CN</CountryCode>
        <CurrentStatus>Active</CurrentStatus>
      </Country>
    </Countries>

    <Countries>
      <Country>
        <CountryCode>AU</CountryCode>
        <CurrentStatus>Cancelled</CurrentStatus>
      </Country>
      <Country>
        <CountryCode>CN</CountryCode>
        <CurrentStatus>Cancelled</CurrentStatus>
      </Country>
      <Country>
        <CountryCode>US</CountryCode>
        <CurrentStatus>Active</CurrentStatus>
      </Country>
    </Countries>

    <Countries xsi:nil="true" />
</Root>

My problem here is that Countries can have Country as single and array as you can see. To get it working I have it as object type now but it is hard to handle. What is the best solution to fix this? I'm converting it to json since all our other systems use that and this is the only file we have that is XML.

public class Country
{

    [JsonProperty("CountryCode")]
    public string CountryCode { get; set; }

    [JsonProperty("CurrentStatus")]
    public string CurrentStatus { get; set; }
}

public class CountryInfo
{
    [JsonProperty("Country")]
    public object Country { get; set; }

    //Does not work
    //[JsonProperty("Country")]
    //public IList<Country> Country { get; set; }
}

public class Root
{
    [JsonProperty("Countries")]
    public IList<CountryInfo> Countries { get; set; }
}

public class ExampleCountry
{
    [JsonProperty("Root")]
    public Root Root { get; set; }
}

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
string json = JsonConvert.SerializeXmlNode(xmlDoc);
var exampleCountries = JsonConvert.DeserializeObject<ExampleCountry>(json);

Update:

If I enable public IList<Country> Country { get; set; } I get the following error:

Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IList`1[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • It's not because your array only contains one element that it can not be an array if it contains no element or only one. – Laurent Lequenne Aug 30 '17 at 12:14
  • Why doesn't `public IList Country { get; set; }` not work? How exactly does it not work? – Ashley Pillay Aug 30 '17 at 12:15
  • @AshleyPillay I'm assuming what he meant that it doesn't always work as at time he could receive a single object (ie: public Country Country {get; set; }) -- not an array with a single object inside it. – hsoesanto Aug 30 '17 at 12:17
  • `My problem here is that Countries can be both single and array as you can see.` Can you make it more explicit which is the single one? _I can't see a single one there._ – mjwills Aug 30 '17 at 12:22
  • @mjwills Check Country for Countries. As you can se there can be either a single item or several and this is causing a problem when deserializing. – Ogglas Aug 30 '17 at 12:26
  • @mjwills Absolutely but `DeserializeObject` throws the error that I printed with the example code above anyway. It does not understand that the single object should be an array. – Ogglas Aug 30 '17 at 12:30
  • @mjwills The problem I had was handling when a XML property can be either single or array. Have a look at the solution below and perhaps it will clear. – Ogglas Aug 30 '17 at 12:37

1 Answers1

1

Solved it using this answer:

https://stackoverflow.com/a/18997172/3850405

public class CountryInfo
{
    [JsonProperty("Country")]
    [JsonConverter(typeof(SingleOrArrayConverter<Country>))]
    public IList<Country> Country { get; set; }
}

public class SingleOrArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<T>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>();
        }
        return new List<T> { token.ToObject<T>() };
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}
Ogglas
  • 62,132
  • 37
  • 328
  • 418