5

I have a class that looks like this (heavily simplified):

public class Foo
{
    public enum Value
    {
        ValueOne,
        ValueTwo
    }

    [XmlAttribute]
    public Value Bar { get; set; }
}

I'm receiving an XML file from an external source. Their documentation states that the Foo element will only ever have "ValueOne" or "ValueTwo" in the Bar attribute (they don't supply an XSD).

So, I deserialize it like this:

 var serializer = new XmlSerializer(typeof(Foo));
 var xml = "<Foo Bar=\"ValueTwo\" />";
 var reader = new StringReader(xml);

 var foo = (Foo)serializer.Deserialize(reader);

... and that all works.

However, last night, they sent me some XML looking like this instead, and my deserialization failed (as it should):<Foo Bar="" />

Is there a good way to defensively code around this? Ideally I'd like to say something like "default to ValueOne, if something goes wrong here". I don't want to throw away the whole XML file, because a single attribute was mangled.

NeilD
  • 2,278
  • 3
  • 24
  • 28
  • http://stackoverflow.com/a/1266758/485076 – sll Oct 31 '12 at 14:22
  • You could try creating an XML object from your input string first, then iterate over the nodes and replace all empty values with ValueOne. – FLClover Oct 31 '12 at 14:23

3 Answers3

4

you can set you enum like this , so this will set "" value of enum to Unknown = 0 somewhat like default value

public enum Foo
{
   [XmlEnum(Name = "")]
   Unknown =0,
   [XmlEnum(Name = "Single")]
   One,
   [XmlEnum(Name = "Double")]
   Two   
}

more detail check : XmlEnumAttribute Class

Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
  • 4
    Hmm... That's a decent option, but it does require that I know all of the potential bad values ahead of time. I'd like something that will cope if they send "", or "ValueThree", or "SomethingTotallyRandom". – NeilD Oct 31 '12 at 14:32
1

You can manually parse enum value by creating another property with the same XmlAttribute name:

public enum Value
{
    // Default for unknown value
    Unknown,
    ValueOne,
    ValueTwo
}

[XmlIgnore]
public Value Bar { get; set; }

[XmlAttribute("Bar")]
public string _Bar
{
    get { return this.Bar.ToString(); }
    set { this.Bar = Enum.TryParse(value, out Value enumValue) ? enumValue : Value.Unknown; }
}

Usage the same as your before

var serializer = new XmlSerializer(typeof(Foo));
var xml = "<Foo Bar=\"invalid value\" />";
var reader = new StringReader(xml);
var foo = (Foo)serializer.Deserialize(reader);
Save
  • 1,376
  • 2
  • 12
  • 26
  • Nearly 10 years later, and I've just gone back to check the code I wrote at the time... It's almost identical to your answer. Nice to finally mark this as answered! – NeilD Aug 22 '22 at 08:42
  • @NeilD I hope this answer will help someone else in next 10 years – Save Aug 22 '22 at 13:54
0

Shoot down XmlSerializer.. Use LINQ2XML for this simple task

XElement doc=XElement.Load("yourStreamXML"); 

List<Foo> yourList=doc.Descendants("Foo")
.Select(x=>
new Foo
{
    Bar=(Enum.GetNames(typeof(Value)).Contains(x.Attribute("Bar").Value))?((this.Value)x.Attribute("Bar")):(this.Value.ValueOne);
}
).ToList<Foo>();

So,I am basically doing this

if(Enum.GetNames(typeof(Value)).Contains(x.Attribute("Bar").Value))
//if the xml bar value is a valid enum
    Bar=(this.Value)x.Attribute("Bar");
else//xml bar value is not a valid enum..so use the default enum i.eValueOne
    Bar=this.Value.ValueOne;
Anirudha
  • 32,393
  • 7
  • 68
  • 89