【问题标题】:Handling extra spaces when deserializing XML values to enums在将 XML 值反序列化为枚举时处理额外的空格
【发布时间】:2015-07-06 17:57:50
【问题描述】:

我一直想知道是否可以这样做。

如果 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 值可能会在以后更改。

【问题讨论】:

  • 您可以使用自定义反序列化器在反序列化时“清理”数据。要么是这样,要么是效率极低的 string.replace 在反序列化之前剥离 XML 中的所有空格(我可能会被社区绞死,甚至建议这种替代方案)。
  • 你能展示你用来反序列化的代码吗?这可能就像添加 .Trim() 一样简单
  • 获取更多信息请输入代码
  • 抱歉,我手头没有反序列化代码。虽然,这只是将 XML 响应传递到 deserialize() 方法的标准操作。忽略低效率,去掉所有空格是行不通的,因为大多数 XML 值都需要它们的空格(即大量文本)。

标签: c# xml serialization enums


【解决方案1】:

请试试这个:

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】:

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

【讨论】:

  • 不幸的是,性能是个问题。此外,我无法修剪每个值,因为大多数值都需要与它们一起发送的空格(即大量文本)。我的目标是能够只修剪不包含空格的值,以避免任何错误被抛出。
  • 这不会修剪每个值,它只会修剪名为 Bar 的元素的值。你可以使用任何查询,任何你喜欢的自定义逻辑。与以往一样,尝试各种选项并衡量
  • 哦,是的,我很抱歉,一定是看错了。我可能会接受这个想法。取决于这可以实现多好,以包含所有需要检查的值。明天早上我会告诉你我的进步!
【解决方案3】:

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

一种可能的解决方法是使用add a string-valued property to your class 并手动进行解析。另一种方法是添加一个封装枚举以处理解析的包装器结构:

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

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

【讨论】:

    猜你喜欢
    • 2013-12-04
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多