在将XML值反序列化为枚举时处理额外的空格

本文关键字:处理 空格 枚举 XML 反序列化 在将 | 更新日期: 2023-09-27 18:01:26

我一直在想是否有可能做到这一点。

当XML响应有不正确的值需要映射到枚举时,这将是一个很大的帮助。

我正在处理的具体情况是,当一个期望值有一个末尾空格,而枚举期望它没有。

XML:

<Foo>
    <Bar>EnumValue </Bar>
</Foo>

枚举:

public enum MyEnum
{
    [XmlEnum("EnumValue")]
    EnumValue
}
类:

public class Foo
{
    [XmlElement("Bar")]
    public MyEnum myEnum { get; set; }
}

我已经研究过使用自定义属性(而不是"XmlEnum")来修剪值,但在反序列化过程中似乎没有达到。

是否有一种方法可以在反序列化之前/期间修剪XML值(当需要时),以便值可以正确映射到枚举?

我应该补充一点,我不能对XML的发送方式做任何改变,我只能处理响应。

同样,简单地将属性参数更改为[XmlEnum("EnumValue ")]可以修复此问题,但这并不令人满意,因为XML值可以在以后更改。

在将XML值反序列化为枚举时处理额外的空格

请试试:

public class Foo
{
    [XmlIgnore]
    public MyEnum myEnum { get; set; }
    [XmlElement("Bar")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public string _myEnum
    {
        get { return myEnum.ToString(); }
        set { myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), value.Trim()); }
    }
}

如果XML不是很大,并且/或者性能不太可能成为问题,您可以简单地使用LINQ to XML解析它,并在使用XmlSerializer进行反序列化之前修复任何不正确的值:

var doc = XDocument.Parse(xml);
foreach (var bar in doc.Descendants("Bar"))
{
    bar.Value = bar.Value.Trim();
}
using (var reader = doc.CreateReader())
{
    var obj = serializer.Deserialize(reader);
}

不幸的是,没有针对未知enum值触发的事件,无法让您替换自己的解析算法。此外,XmlEnumAttribute不设置AttributeUsage.AllowMultiple = true,因此您不能添加多个具有各种前后空格组合的枚举别名。

一种可能的解决方法是在类中添加字符串值属性并手动进行解析。另一种方法是添加封装枚举以处理解析的包装器结构:

public class Foo
{
    [XmlIgnore]
    public MyEnum myEnum { get; set; }
    [XmlElement("Bar")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public XmlEnumWrapper<MyEnum> myEnumXml { get { return myEnum; } set { myEnum = value; } }
}
public struct XmlEnumWrapper<TEnum> : IEquatable<XmlEnumWrapper<TEnum>> where TEnum : struct, IConvertible, IComparable, IFormattable
{
    TEnum value;
    public XmlEnumWrapper(TEnum value)
    {
        this.value = value;
    }
    public static implicit operator TEnum(XmlEnumWrapper<TEnum> wrapper)
    {
        return wrapper.Value;
    }
    public static implicit operator XmlEnumWrapper<TEnum>(TEnum anEnum)
    {
        return new XmlEnumWrapper<TEnum>(anEnum);
    }
    public static bool operator ==(XmlEnumWrapper<TEnum> first, XmlEnumWrapper<TEnum> second)
    {
        return first.Equals(second);
    }
    public static bool operator !=(XmlEnumWrapper<TEnum> first, XmlEnumWrapper<TEnum> second)
    {
        return !first.Equals(second);
    }
    [XmlIgnore]
    public TEnum Value { get { return value; } private set { this.value = value; } }
    [XmlText]
    public string ValueString
    {
        get
        {
            return Value.ToString();
        }
        set
        {
            // See here if one needs to parse XmlEnumAttribute attributes
            // http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
            value = value.Trim();
            Value = (TEnum)Enum.Parse(typeof(TEnum), value, false);
        }
    }
    #region IEquatable<XmlEnumWrapper<TEnum>> Members
    public bool Equals(XmlEnumWrapper<TEnum> other)
    {
        return EqualityComparer<TEnum>.Default.Equals(Value, other.Value);
    }
    #endregion
    public override bool Equals(object obj)
    {
        if (obj is XmlEnumWrapper<TEnum>)
            return Equals((XmlEnumWrapper<TEnum>)obj);
        return Value.Equals(obj);
    }
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
    public override string ToString()
    {
        return Value.ToString();
    }
}

这还允许您在必要时添加同义词处理或处理未知值而不会抛出异常。