在 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.
我在反序列化来自 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 节点名称和元素与属性状态。
但如
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.