Handling extra spaces when deserializing XML values to enums

纵然是瞬间 提交于 2020-01-05 03:10:10

问题


I've been wondering if it's possible to do this.

It would be a great help in cases where an XML response has incorrect values that are needing to be mapped to enums.

The case I'm dealing with specifically is when an expected value has a trailing space and the enum is expecting it without.

XML:

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

Enum:

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

Class:

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

I've investigated using a custom attribute (instead of "XmlEnum") to trim the values but it doesn't seem to be reached during the deserialization.

Is there a way to trim XML values (when needed) before/during deserialization so that the value can be mapped to the enum correctly?

-

I should add that I can't make any changes to how the XML is sent, I can only deal with the response.

Also, simply changing the attribute parameter to [XmlEnum("EnumValue ")] fixes the issue, but this is not satisfactory as the XML value could be altered at a later date.


回答1:


Please try this:

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



回答2:


If the XML isn't huge and/or performance isn't likely to be an issue, you could simply parse this with LINQ to XML and fix-up any values that aren't correct before deserializing using your 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);
}



回答3:


Unfortunately there's no event that is fired on an unknown enum value that lets you substitute your own parsing algorithm. Also, XmlEnumAttribute doesn't set AttributeUsage.AllowMultiple = true so you can't add multiple enum aliases with various combinations of leading and trailing spaces.

One possible workaround would be to add a string-valued property to your class and do the parsing manually. Another would be to add a wrapper struct that encapsulates the enum to handle the parsing:

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

This also allows you to add synonym processing or handle unknown values without throwing an exception if it becomes necessary.



来源:https://stackoverflow.com/questions/31252551/handling-extra-spaces-when-deserializing-xml-values-to-enums

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