简体   繁体   中英

How to deserialise an enum value from either a string or an int in XML

I know that an enum value can be deserialised from either a string or an integer value but not both. I want to write some code which handles an enum deserialisation no matter the value in the XML is an integer or a string. An example is given below with sample data.

Data Strcuture

class Employee
{
  public string Name { get; set; }
  public RankType Rank { get; set; }
}
enum RankType
{
  Junior,
  MidLevel,
  Senior,
  Executive
}

Possible XML data - sample 1

<employee>
  <name>John Doe</name>
  <rank>Executive</rank>
</employee>

Possible XML data - sample 2

<employee>
  <name>John Doe</name>
  <rank>3</rank>
</employee>

I wrote this code which works fine for sample 1, but crashes for sample 2:

var xs = new XmlSerializer(typeof(Employee));
XmlDocument xml = new XmlDocument();
xml.LoadXml(empRequest);
var node = xml.SelectSingleNode("/EmpRequest"); // <-- the exact path here is irrelevant
var sr = new StringReader(xml.InnerXml);
var obj = (Employee)xs.Deserialize(sr); // <-- Exception here

The exception message is: " '3' is not a valid value for RankType "

You can either make your Employee class IXmlSerializable and fully control how it's serialized and deserialized.
Or you can prepare your xml document before you pass it to XmlSerializer .
For example, search for all employee\rank nodes and if they contain integer change it to name.

var xs = new XmlSerializer(typeof(Employee));
XmlDocument xml = new XmlDocument();
xml.LoadXml(empRequest);
// update employee/rank
foreach (XmlElement rankNode in xml.SelectNodes("//employee/rank"))
    if (Int32.TryParse(rankNode.InnerText, out int rank) && Enum.IsDefined(typeof(RankType), rank))
       rankNode.InnerText = Enum.GetName(typeof(RankType), rank);
// loading further
var node = xml.SelectSingleNode("/EmpRequest");
var sr = new StringReader(node.InnerXml);
var obj = (Employee)xs.Deserialize(sr); 

The following will work with either the name or integer value

    class Employee
    {
        public string Name { get; set; }
        private RankType Rank { get; set; }
        
        [XmlElement("Rank")]
        public string _Rank {
        get { 
            return Rank.ToString();
            //use following if you want integer when serializing
            //return ((int)Rank).ToString();
        }
        set 
        {
            int number = 0;
            Boolean numeric = int.TryParse(value, out number);
            if (numeric)
            {
                Rank = (RankType)number;
            }
            else
            {
                Rank = (RankType)Enum.Parse(typeof(RankType), value);
            }
                
        } 
    }
    enum RankType
    {
        Junior,
        MidLevel,
        Senior,
        Executive
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM