如何在 xml 反序列化期间忽略无效的枚举值?

How to ignore invalid enum values during xml deserialization?

我想将一个 xml 文档反序列化为一个 class,它是由相关的 xsd 文件生成的。我无法控制 xml 文件的内容。

在反序列化过程中,我运行出现异常,因为xml文档中的枚举值不符合xsd的要求。我不想破坏,而是希望反序列化继续,并且只为任何此类错误采用默认值。有什么办法可以实现这种行为吗?


编辑: 为了澄清,我想要实现的目标是:我想从数字发票中读取数据。所以 xml 文件的创建是某种黑盒,可能包含 flase 值,即使结构符合标准。但这并不意味着每一种价值观都存在缺陷。该异常阻止我读取正确的值,所以我只想在发生此类错误时通过以某种方式插入默认值来完成反序列化。

无论是将值标记为过时,还是用 XmlIgnore 标记它们都不会起作用,因为我收到的下一个 xml 可能包含正确的值。

我希望这有助于澄清问题。


现在,我正在使用 System.Xml.Serialization dll,但我愿意实施任何可以帮助我实现所需行为的库。

我收到异常:

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

抛出异常的代码:

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

我知道代码没有太大帮助,所以我将添加当前有问题的枚举:

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,
    }

这些是使用 xsd 命令行工具自动生成的: https://docs.microsoft.com/de-de/dotnet/standard/serialization/xml-schema-definition-tool-xsd-exe

我需要反序列化的 xml 为我提供了一个“1”,显然是一个无效值。我仍然需要从 xml 访问其他有效值并提供指示哪些值有缺陷的方法。

您可以将成员标记为过时

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

更多信息 - docs

正如 Martin 所提到的,如果没有适当的上下文或示例代码,回答起来有点困难。但是,您可能需要查看模型的 属性 上的 XmlIgnoreAttribute 装饰器。有关如何使用的更多详细信息,请参阅下面的 URL 和代码示例:

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;
}

您可以使用 Extended Xml Serializer library (avaliable via nuget) instead of the default XmlSerializer, with a custom converter 设置默认值以防出现错误。

我建议你把Enum的值存成一个字符串,然后自己解析。这个实现起来比较简单,举个例子:

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);
}

或者,如果您愿意,也可以设置可为空的枚举

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);
}

我仍然无法找到我所希望的简单答案,但设法找到了适合我的解决方法。我最终根据可能的值预先验证了 XML 文件中的每个枚举。如果 XML 与枚举不匹配,我将错误的值和节点保存到验证结果集中,并用枚举默认值覆盖 xml。