在 C# 中使用属性反序列化 XML

Deserialize XML with Attributes in C#

我在反序列化来自 API 调用的 XML 响应时遇到问题。我的 'Option' 对象的 属性 'Description' 为空。

下面是 XML 的示例:

<vehicle found="1">
   <description>VehicleDescText</description>
   <buildDate>2000-11-20</buildDate>
   <modelYear>2001</modelYear>
   <optionList>
      <option code="UH8">OptionDesc1</option>
      <option code="UH8">OptionDesc2</option>
   </optionList>
</vehicle>

这是 C# 的示例 类:

[DataContract]
[XmlRoot("vehicle")]
public class Vehicle
{
    [DataMember]
    [XmlAttribute("found")]
    public bool Found { get; set; }

    [DataMember]
    [XmlElement("description")]
    public string Description { get; set; }

    [DataMember]
    [XmlElement("buildDate")]
    public string BuildDate { get; set; }

    [DataMember]
    [XmlElement("modelYear")]
    public string ModelYear { get; set; }

    [DataMember]
    [XmlElement("optionList")]
    public List<Option> OptionList { get; set; }
}

public class Option
{
    [DataMember]
    [XmlAttribute("code")]
    public string Code { get; set; }

    [DataMember]
    [XmlElement("option")]
    public string Description { get; set; }
}

反序列化对象如下所示:

var xmlDeserializer = new RestSharp.Deserializers.XmlDeserializer();
results = xmlDeserializer.Deserialize<Vehicle>(response);

我哪里错了?由于我不想修改底层数据模型,我可以添加或修改哪些属性来解决问题?

阅读文档:https://github.com/restsharp/RestSharp/wiki/Deserialization

Description 属性 更改为 Value 属性 它将起作用(在 Option class 中)。

无法给您更好的答案,因为我从未使用过 RestSharp :)

在 XML 中,您需要的值不是内部 XmlElement - 它是当前 XmlElement 的值。

您可以将 Option class' Description 属性 标记为 XmlText 而不是 XmlElement

related answer

您已使用 XML serializer attributes and data contract attributes, but the deserializer you are using, RestSharp.Deserializers.XmlDeserializer 标记您的类型,不支持这些属性。

相反,如其 documentation, it supports the [DeserializeAs] 属性中所述,该属性允许控制 XML 节点名称和元素与属性状态。

但如 as well as this older question 中所述,文档中有一个关于将元素值反序列化为 属性 值的特殊情况:

If the XML returned is like this:

<Response>Hello world</Response>

There's no way to directly represent that in a C# class:

public class Response {
}

You need something to hold the value of the Response element. In this case, add a property called Value and it will be populated:

public class Response {
     public string Value { get; set; }
}

This condition is checked for between searching for matching element names and matching attribute names.

即如果您将 Description 重命名为 Value,您将能够成功反序列化 XML。 (Sample fiddle #1.)

但是,您似乎不想重命名您的 Description 属性。如果是这样,您可以改为对它应用 [DeserializeAs(Name = "Value")],特殊情况将再次应用:

public class Option
{
    public string Code { get; set; }

    [DeserializeAs(Name = "Value")]
    public string Description { get; set; }
}

示例 fiddle #2.

最后,作为替代解决方案,您可以切换到 RestSharp.Deserializers.DotNetXmlDeserializer and use regular XmlSerializer attributes, specifically [XmlText]。因此您的代码将变为:

var xmlDeserializer = new RestSharp.Deserializers.DotNetXmlDeserializer();
var results = xmlDeserializer.Deserialize<Vehicle>(response);

你的类型看起来像:

[XmlRoot("vehicle")]
public class Vehicle
{
    [XmlAttribute("found")]
    public bool Found { get; set; }

    [XmlElement("description")]
    public string Description { get; set; }

    [XmlElement("buildDate")]
    public string BuildDate { get; set; }

    [XmlElement("modelYear")]
    public string ModelYear { get; set; }

    [XmlArray("optionList")]
    [XmlArrayItem("option")]
    public List<Option> OptionList { get; set; }
}

public class Option
{
    [XmlAttribute("code")]
    public string Code { get; set; }

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

样本fiddle #3.