使用因属性而异的元素反序列化 XML
Posted
技术标签:
【中文标题】使用因属性而异的元素反序列化 XML【英文标题】:Deserialize XML with elements that differ by attribute 【发布时间】:2021-11-12 03:44:42 【问题描述】:我有这个 XML 的 sn-p(实际上是 XBRL,但那是基于 XML)
<xbrl>
<context id="Context_Duration" />
<context id="Context_Instant_Begin" />
<context id="Context_Instant_End" />
<ConstructionDepotSpecification>
<ConstructionDepotLabel contextRef="Context_Duration">depot</ConstructionDepotLabel>
<ConstructionDepotBalance contextRef="Context_Instant_Begin">45000</ConstructionDepotBalance>
<ConstructionDepotBalance contextRef="Context_Instant_End">42000</ConstructionDepotBalance>
</ConstructionDepotSpecification>
</xbrl>
(为清楚起见,删除了其他内容和 xml 命名空间声明)
我想将其反序列化为一个类,但我不确定如何处理 ConstructionDepotBalance 元素。如果我定义一个属性 ConstructionDepotBalance ,它将只取第一个元素的值,所以我认为我应该创建两个属性,一个用于开始值,一个用于结束值。 所以这个类应该是这样的
[XmlRoot(ElementName = "xbrl")]
public partial class Taxonomy
[XmlElement]
public List<ConstructionDepotSpecification> ConstructionDepotSpecification get; set;
public partial class ConstructionDepotSpecification
public string ConstructionDepotLabel get; set;
public long? ConstructionDepotBalanceBegin get; set;
public long? ConstructionDepotBalanceEnd get; set;
因此,具有 Context_Instant_Begin 属性的元素应反序列化为 ConstructionDepotBalanceBegin,而具有 Context_Instant_End 属性的其他元素应反序列化为 ConstructionDepotBalanceEnd。
这有可能实现吗?我应该为此使用 IXmlSerializable 实现吗?
【问题讨论】:
【参考方案1】:我的第一种方法:
您可以先解析 XML-String 并替换
[ConstructionDepotBalance contextRef="Context_Instant_Begin"]
与
[ConstructionDepotBalanceBegin]
(与ConstructionDepotBalanceEnd
相同)。
在第二步中,您将反序列化 XML 字符串。
【讨论】:
谢谢,这可能适用于简化的示例,但真正的 XML 更复杂,所以我不想那样做 也许这可以帮助您在第一步解析属性。在第二步(如果需要),您可以将结果转换为您想要的数据结构。 ***.com/questions/14245846/…【参考方案2】:我对 IXmlSerializable 接口进行了一些实验,并提出了这个实现:
public void ReadXml(XmlReader reader)
reader.ReadStartElement();
while (!reader.EOF)
var ctx = reader.GetAttribute("contextRef");
if (ctx == "Context_Duration")
string propName = reader.Name;
var propInfo = GetType().GetProperty(propName);
Type propType = propInfo.PropertyType;
if (propType.GenericTypeArguments.Length > 0)
propType = propType.GenericTypeArguments[0];
var value = reader.ReadElementContentAs(propType, null);
propInfo.SetValue(this, value);
else if (ctx == "Context_Instant_Begin")
string propName = reader.Name + "Begin";
var propInfo = GetType().GetProperty(propName);
var value = reader.ReadElementContentAsLong();
propInfo.SetValue(this, value);
else if (ctx == "Context_Instant_End")
string propName = reader.Name + "End";
var propInfo = GetType().GetProperty(propName);
var value = reader.ReadElementContentAsLong();
propInfo.SetValue(this, value);
if (reader.NodeType == XmlNodeType.EndElement)
reader.ReadEndElement();
break;
不确定这是否是解决此问题的最佳解决方案,但目前它可以满足我的需求。
【讨论】:
以上是关于使用因属性而异的元素反序列化 XML的主要内容,如果未能解决你的问题,请参考以下文章
如何在c#中使用具有相同名称但不同属性和结构的元素反序列化XML