How to ignore invalid enum values during xml deserialization?

China☆狼群 提交于 2021-01-28 18:38:44

问题


I want to deserialize an xml document to a class, which is genereated by the concerning xsd files. I don't have control over the contents of the xml-file.

During deserialization I run into an exception, because an enum value in the xml document does not meet the requiremnts of the xsd. Instead of breaking, i would like the deserialization to continue and just take the default value for any such errors. Is there any way to accomplish this behaviour?


edit: For clarification, what i am trying to achieve: I want to read data from digital invoices. So the creation of the xml file is some kind of blackbox and can contain possibly flase values, even if the structure meets the standards. But that does not mean, that every value is flawed in that way. The exception prevents me from reading the correct values so i just want the deserialization to finish by somehow inserting the default values if such an error occurs.

Neither marking the values as obsolete, nor flagging them with XmlIgnore won't work, because the next xml i receive could contain correct values.

I hope that helped clarifying the problem.


Right now, im using the System.Xml.Serialization dll, but im willing to implement any library which can help me achieve the wanted behaviour.

The exception im getting:

"System.InvalidOperationException: Instance validation error: 'x' is not a valid value for xType.."

The code that throws the exception:

XmlSerializer serializer = new xml.XmlSerializer(typeof(MyType));
MyType invoice = serializer.Deserialize(memoryStream) as MyType;

I know the code does not help very much, so I'll add the enum, that is currently problematic:

public enum PaymentMeansCodeContentType
    {

        [System.Xml.Serialization.XmlEnumAttribute("10")]
        Item10,

        [System.Xml.Serialization.XmlEnumAttribute("20")]
        Item20,

        [System.Xml.Serialization.XmlEnumAttribute("30")]
        Item30,

        [System.Xml.Serialization.XmlEnumAttribute("48")]
        Item48,

        [System.Xml.Serialization.XmlEnumAttribute("49")]
        Item49,

        [System.Xml.Serialization.XmlEnumAttribute("57")]
        Item57,

        [System.Xml.Serialization.XmlEnumAttribute("58")]
        Item58,

        [System.Xml.Serialization.XmlEnumAttribute("59")]
        Item59,

        ZZZ,
    }

These are autogenerated from using the xsd command line tool: https://docs.microsoft.com/de-de/dotnet/standard/serialization/xml-schema-definition-tool-xsd-exe

The xml i need to deserialize provides me with a '1', so clearly an invalid value. Still i need to access the other valid values from the xml and provide means for indicating which values are flawed.


回答1:


You can mark the member Obsolete

public enum TypeEnum
{
    Temperature,
    Pressure,
    [Obsolete]
    Humidity
}

More info - docs




回答2:


I still wasn't able to find the simple answer I was hoping for but managed to find a work around that worked for me. I ended up validating every enum in the XML file beforehand against the possible values. If the XML did not match the enum i saved the wrong value and node to a validation result set and overwrote the xml with the enum default value.




回答3:


As Martin mentioned, it's a bit difficult to answer without proper context or sample code. However, you may want to look at the XmlIgnoreAttribute decorator on the property for the model. See the URL & code sample below for more details on how to use:

https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlattributes.xmlignore?view=netframework-4.8

using System;
using System.IO;
using System.Xml.Serialization;

// This is the class that will be serialized. 
public class Group
{
   // The GroupName value will be serialized--unless it's overridden.
   public string GroupName;

   /* This field will be ignored when serialized--
      unless it's overridden. */
   [XmlIgnoreAttribute]
   public string Comment;
}



回答4:


You can use Extended Xml Serializer library (avaliable via nuget) instead of the default XmlSerializer, with a custom converter that will set the default value in case of an error.




回答5:


I suggest you store the value of the Enum as a string, and then parse it yourself. This is relatively simple to implement, here's an example:

public enum MyEnum
{
    Default, //The default value to apply in the event of an invalid Enum value

    [XmlEnumAttribute("10")]
    Item10,

    [XmlEnumAttribute("20")]
    Item20
}

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

    public MyEnum EnumValue => (MyEnum)(typeof(MyEnum).GetFields().FirstOrDefault(f => 
                                   f.GetCustomAttribute<XmlEnumAttribute>()?.Name == Value)?
                                       .GetValue(null) ?? MyEnum.Default);
}

Or if you prefer it you can also set a nullable Enum

public enum MyEnum
{
    [XmlEnumAttribute("10")]
    Item10,

    [XmlEnumAttribute("20")]
    Item20
}

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

    public MyEnum? EnumValue => (MyEnum?)typeof(MyEnum).GetFields().FirstOrDefault(f =>
                                   f.GetCustomAttribute<XmlEnumAttribute>()?.Name == Value)?
                                       .GetValue(null);
}


来源:https://stackoverflow.com/questions/59247332/how-to-ignore-invalid-enum-values-during-xml-deserialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!