[英]How to deserialize a xml string to a set of C# classes without having to declare a lot properties just for xml attributes?
[英]How can I convert an XML without attributes to C# properties?
我无法将我的 XML 转换为 C# object。
我的 XML 看起来像这样:
<metadata>
<item name="Date" type="xs:date"/>
<item name="Hour" type="xs:time"/>
<item name="Group" type="xs:string" length="12"/>
<item name="Status" type="xs:string" length="18"/>
</metadata>
<data>
<row>
<value>2020-05-08</value>
<value>14:00:01</value>
<value>A</value>
<value>Active</value>
</row>
<row>
<value>2020-05-08</value>
<value>14:00:01</value>
<value>B</value>
<value>Inactive</value>
</row>
</data>
</metadata>
我想 map XML 到 c# object 看起来像这样
public class GroupDto
{
public string Date { get; set; }
public string Hour { get; set; }
public string Group { get; set; }
public string Status { get; set; }
}
(日期和时间可以是字符串,没问题)我正在使用 JsonConvert.SerializeXmlNode(doc),但它给了我这个结果:
"data": {
"row": [
{
"value": [
"2020-05-08",
"14:00:01",
"A",
"Active"
]
},
....
我喜欢将 map 的“值”改为 C# object 的相应属性。 有没有一种适当的方法可以使用这种奇怪格式的 XML 来实现这一目标?
如果无法将值与值区分开来,则必须为反序列化制定一些规则。
假设您根本不相信属性的顺序正确,您可以使用以下规则组:
DateTime
':'
而日期不包含。foreach(var row in data.Row){
var temp = new GroupDto();
foreach(var val in row.Value){
if( DateTime.TryParse(val, out DateTime date) )
{
if(val.Contains(':')) //it should be a time
{
temp.Hour = date.ToShortTimeString(); //or keep the datetime format
}
else
{
temp.Hour = date.ToShortDateString();
}
}
//either based status on a list of know status
else if(knowStatus.Contains(val))
{
temp.Status = val;
}
//or base Group detection on string lenght and default the remaining possibility to status
else if(val.lenght>1)
{
temp.Status = val;
}
else {
temp.Group = val;
}
}
// return temp/ yeild return temp/ Add it to a list of result etc
}
请注意,这或多或少是基于无效 Xml 的伪代码。 这看起来就像一旦你添加一个公共根并在最后删除最后一个关闭元......:
[XmlRoot(ElementName="row")]
public class Row {
[XmlElement(ElementName="value")]
public List<string> Value { get; set; }
}
[XmlRoot(ElementName="data")]
public class Data {
[XmlElement(ElementName="row")]
public List<Row> Row { get; set; }
}
如果您信任属性订单,您可以简单地
Data.Row.Select(x => new GroupDto{
Date = x.Value[0],
Hour = x.Value[1],
Group = x.Value[2],
Status = x.Value[3],
} )
如果您不信任属性的顺序,可以尝试以下操作:
var metadata = doc.Root.Element("metadata");
var mapper = metadata.Elements("item")
.Select((i, c) => new { Property = i.Attribute("name").Value, Index = c })
.ToDictionary(i => i.Property, i => i.Index);
var rows = doc.Root.Element("data").Elements("row").Select(r => new GroupDto
{
Date = r.Elements("value").ElementAt(mapper[nameof(GroupDto.Date)]).Value,
Hour = r.Elements("value").ElementAt(mapper[nameof(GroupDto.Hour)]).Value,
Group = r.Elements("value").ElementAt(mapper[nameof(GroupDto.Group)]).Value,
Status = r.Elements("value").ElementAt(mapper[nameof(GroupDto.Status)]).Value,
}).ToList();
它可能不是最佳解决方案,但它以一种不那么复杂的方式为您提供了您想要的东西。
最重要的是,如果您在 xml 中的属性与您的 DTO object 的属性不匹配,您总是可以引入一个额外的映射层。 例如:
var metaMapper = metadata.Elements(ns + "item")
.Select((i, c) => new { Property = i.Attribute("name").Value, Index = c })
.ToDictionary(i => i.Property, i => i.Index);
var metaPropertyMapper = new Dictionary<string, string>
{
{ nameof(GroupDto.Date), "DateInXML" },
{ nameof(GroupDto.Hour), "HourInXML" },
{ nameof(GroupDto.Group), "GroupInXML" },
{ nameof(GroupDto.Status), "StatusInXML" },
};
var rows = doc.Root.Element(ns + "data").Elements(ns + "row").Select(r => new GroupDto
{
Date = r.Elements(ns + "value").ElementAt(metaMapper[metaPropertyMapper[nameof(GroupDto.Date)]]).Value,
Hour = r.Elements(ns + "value").ElementAt(metaMapper[metaPropertyMapper[nameof(GroupDto.Hour)]]).Value,
Group = r.Elements(ns + "value").ElementAt(metaMapper[metaPropertyMapper[nameof(GroupDto.Group)]]).Value,
Status = r.Elements(ns + "value").ElementAt(metaMapper[metaPropertyMapper[nameof(GroupDto.Status)]]).Value,
}).ToList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.