【问题标题】:Deserialize XML with elements that differ by attribute使用因属性而异的元素反序列化 XML
【发布时间】: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 实现吗?

【问题讨论】:

    标签: c# xml xml-deserialization xbrl


    【解决方案1】:

    我的第一种方法:

    您可以先解析 XML-String 并替换

    [ConstructionDepotBalance contextRef="Context_Instant_Begin"]
    

    [ConstructionDepotBalanceBegin]
    

    (与ConstructionDepotBalanceEnd相同)。

    在第二步中,您将反序列化 XML 字符串。

    【讨论】:

    • 谢谢,这可能适用于简化的示例,但真正的 XML 更复杂,所以我不想那样做
    • 也许这可以帮助您在第一步解析属性。在第二步(如果需要),您可以将结果转换为您想要的数据结构。 stackoverflow.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;
            }
        }
    }
    

    不确定这是否是解决此问题的最佳解决方案,但目前它可以满足我的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      • 2012-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多