【问题标题】:Deserialize XML with Attributes in C#在 C# 中使用属性反序列化 XML
【发布时间】:2017-10-30 20:37:05
【问题描述】:

我在反序列化来自 API 调用的 XML 响应时遇到问题。我的“选项”对象的属性“描述”为空。

以下是 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);

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

【问题讨论】:

标签: c# xml deserialization restsharp


【解决方案1】:

您已经用XML serializer attributes 和data contract attributes 标记了您的类型,但是您使用的反序列化器RestSharp.Deserializers.XmlDeserializer 不支持这些属性。

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

但正如@apocalypse's answer 和this older question 中所述,文档中有一个关于将元素值反序列化为属性值的特殊情况:

如果返回的 XML 是这样的:

<Response>Hello world</Response>

没有办法在 C# 类中直接表示它:

public class Response {
}

您需要一些东西来保存 Response 元素的值。在这 在这种情况下,添加一个名为 Value 的属性,它将被填充:

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

在搜索匹配元素之间检查此条件 名称和匹配的属性名称。

即如果您将 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 并使用常规XmlSerializer 属性,特别是[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。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 如果在不更改属性名称的情况下无法完成此操作,我会尝试一下。谢谢!
    • 遗憾的是,该属性必须命名为 Value。
    • @MikeViscontini: 用户 dbc 添加了更好的答案。
    【解决方案3】:

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

    您可以使用XmlText 而不是XmlElement 来标记Option 类的Description 属性。

    见related answer。

    【讨论】:

    • 谢谢!我明天会试试这个以及启示录的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多