【问题标题】:Deserializing duplicate XML elements with unique attributes反序列化具有唯一属性的重复 XML 元素
【发布时间】:2014-11-16 18:32:16
【问题描述】:

我有以下 XML 结构:

<Response>
  <Value Name="ID">1</Value>
  <Value Name="User">JSmith</Value>
  <Value Name="Description">Testing 123</Value>
</Response>

我怎样才能反序列化它,以便值名称是类的属性,而文本值是属性的值?

请注意,值名称永远不会改变,因此Name="ID" 将始终存在,例如。

到目前为止,这是我的课:

[Serializable]
[XmlRoot("Response")]
public class ReportingResponse
{
    // [What goes here?]
    public string ID { get; set; }

    // [...]
    public string User { get; set; }

    // [...]
    public string Description { get; set; }
}

【问题讨论】:

  • 我假设您使用的是XmlSerializer。对吗?
  • @dbc 是的,没错。

标签: c# xml xml-serialization xmlserializer


【解决方案1】:

XML 被构造为名称/值对的集合,而不是具有预定义属性的类,这样反序列化它会更容易、更自然。

如果您决定反序列化为一个类,假设您使用的是XmlSerializer,您可以为此目的引入名称/值对的代理数组,如下所示:

public class NameValuePair
{
    [XmlAttribute]
    public string Name { get; set; }

    [XmlText]
    public string Value { get; set; }

    public override string ToString()
    {
        return string.Format("Name={0}, Value=\"{1}\"", Name, Value);
    }
}

[Serializable]
[XmlRoot("Response")]
public class ReportingResponse
{
    [XmlElement(ElementName="Value")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public NameValuePair[] XmlNameValuePairs
    {
        get
        {
            return NameValuePairExtensions.GetNamedValues(this).ToArray();
        }
        set
        {
            NameValuePairExtensions.SetNamedValues(this, value);
        }
    }

    [XmlIgnore]
    public string ID { get; set; }

    [XmlIgnore]
    public string User { get; set; }

    [XmlIgnore]
    public string Description { get; set; }
}

然后进行一些反射以自动加载数组:

public static class NameValuePairExtensions
{
    public static List<NameValuePair> GetNamedValues<T>(T obj)
    {
        if (obj == null)
            throw new ArgumentNullException();
        var type = obj.GetType();
        var properties = type.GetProperties();
        List<NameValuePair> list = new List<NameValuePair>();
        foreach (var prop in properties)
        {
            if (prop.PropertyType == typeof(string))
            {
                var getter = prop.GetGetMethod();
                var setter = prop.GetSetMethod();

                if (getter != null && setter != null) // Confirm this property has public getters & setters.
                {
                    list.Add(new NameValuePair() { Name = prop.Name, Value = (string)getter.Invoke(obj, null) });
                }
            }
        }
        return list;
    }

    public static void SetNamedValues<T>(T obj, IEnumerable<NameValuePair> values)
    {
        if (obj == null || values == null)
            throw new ArgumentNullException();
        var type = obj.GetType();
        foreach (var value in values)
        {
            var prop = type.GetProperty(value.Name);
            if (prop == null)
            {
                Debug.WriteLine(string.Format("No public property found for {0}", value));
                continue;
            }
            try
            {
                prop.SetValue(obj, value.Value, null);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception setting " + value.ToString() + " : \n" + ex.ToString());
            }
        }
    }
}

这将使用所有字符串值的属性名称和值填充数组。您可能想要更智能的东西,在这种情况下,手动填充数组,使用自定义属性标记属性以指示要导出的属性,或者其他更合适的方法。

【讨论】:

  • 我认为是这样的。谢谢。但是,这可行,我认为一种更简单的方法(至少对于我的实现而言)是创建一个“Value”类,将结果存储在一个数组中,然后使用 Linq 将属性引用的 Getter 放入数组中(例如public string ID { get { return myValues.FirstOrDefault(v =&gt; v.Name == "ID"); } }).
  • [XmlText] 是解决我的问题的关键。这就是让您可以在元素中放置一个值而不会将该变量名称变为新元素的原因。
猜你喜欢
  • 2015-09-24
  • 2012-12-24
  • 1970-01-01
  • 2012-05-09
  • 2017-11-07
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多