繁体   English   中英

c#使用IXmlSerializable反序列化

[英]c# Deserialize with IXmlSerializable

我有这样的xml:

    <data>    
  <audit_values>
    <audit_value>
      <channel>2</channel>
      <week>
        <mo_th>6,501698000000</mo_th>
        <fr>8,414278000000</fr>
        <sa>9,292674000000</sa>
        <sun>8,551982000000</sun>
        <holid>7,164605000000</holid>
      </week>
    </audit_value>
    <audit_value>
      <channel>1</channel>
      <week>
        <mo_th>6,501698000000</mo_th>
        <fr>8,414278000000</fr>
        <sa>9,292674000000</sa>
        <sun>8,551982000000</sun>
        <holid>7,164605000000</holid>
      </week>
    </audit_value>
  </audit_values>
</data>

我需要将它反序列化为课堂。 但问题是,那一周将来会发生变化(它将包含更多元素,以及我不知道的名称)

数据:

[XmlRoot("data")]
public class Data
{
    [XmlArray("audit_values")]
    [XmlArrayItem("audit_value", IsNullable = true)]
    public AuditValue[] AuditValues { get; set; }
}

AuditValue:

[XmlRoot("audit_value")]
public class AuditValue
{
    [XmlElement("week", typeof(TVR))]
    public Week Week;
}

周:

    [XmlRoot("week")]
public class Week : IXmlSerializable
{
    public Dictionary<string, double> Values = new Dictionary<string, double>();

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        reader.Read();
        var sub = reader.ReadSubtree();
        do
        {
            if (sub.NodeType == XmlNodeType.Element)
            {
                string name = sub.Name;
                string val = sub.ReadElementContentAsString();
                Values.Add(name, Convert.ToDouble(val));
            }
        } while (sub.Read());
    }

    public void WriteXml(XmlWriter writer)
    {

    }
}

但是在反序列化之后,我只有一个元素只有一个在字典值中被记录。 我做错了什么?

GitHub: https//github.com/olegletynain/XmlTest/tree/master/XmlTestRead

我在评论部分根据@Matthew Whited的想法调整了你的ReadXml方法,以下方法完成了这项工作:

public void ReadXml(XmlReader reader)
{
    Values = XElement.Parse(reader.ReadOuterXml())
        .Elements()
        .ToDictionary(k => k.Name.ToString(), v => double.Parse(v.Value));
}

作为旁注,您只需要在实际根元素上使用XmlRoot而不是每个类,因此我将它从AuditValue和Week中删除。 我也不知道TVR是什么。 它没有用“typeof(TVR)”编译,所以我也删除了它。

为了完整起见,这是我的课程版本:

[XmlRoot("data")]
public class Data
{
    [XmlArray("audit_values")]
    [XmlArrayItem("audit_value", IsNullable = true)]
    public AuditValue[] AuditValues { get; set; }
}

public class AuditValue
{
    [XmlElement("week")]
    public Week Week;
}

public class Week : IXmlSerializable
{
    public Dictionary<string, double> Values = new Dictionary<string, double>();

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        Values = XElement.Parse(reader.ReadOuterXml())
            .Elements()
            .ToDictionary(k => k.Name.ToString(), v => double.Parse(v.Value));
    }

    public void WriteXml(XmlWriter writer)
    {

    }
}

您应该考虑使用DataContractSerializer而不是XmlSerializer,并在DataContract类上实现IExtensibleDataObject接口。

实现IExtensibleDataObject允许DataContract类在ExtensionData字段中保留未知信息,这可以防止在反序列化的XML包含未知元素时丢失,然后重新序列化并保存。

您的Audit类看起来像这样:

[DataContract(Name = "audit_value", Namespace = "")]
public class AuditValue : IExtensibleDataObject
{
    [DataMember(Name = "channel")]
    public int Channel { get; set; }

    [DataMember(Name = "week")]
    public Week Week { get; set; }

    public ExtensionDataObject ExtensionData { get; set; }
}

[DataContract(Name = "week", Namespace = "")]
public class Week : IExtensibleDataObject
{
    [DataMember(Name = "mo_th")]
    public Decimal MondayThroughThursday { get; set; }

    public ExtensionDataObject ExtensionData { get; set; }
}

您仍然需要更新代码以将其他元素反序列化为POCO,但至少基础数据将一直存在,直到您解决它为止。

试试这个。 XmlElement消除了一些你没有的标签。 在值的末尾你有一个额外的's'。

From 
    [XmlArray("audit_values")]
    [XmlArrayItem("audit_value", IsNullable = true)]
    public AuditValue[] AuditValues { get; set; }
​To
    [XmlElement("audit_value")]
    public AuditValue[] AuditValues { get; set; }

错误是在ReadXml方法中,现在我将其更改为:

    public void ReadXml(XmlReader reader)
    {
        reader.Read();
        do
        {
            if (!reader.IsEmptyElement)
            {
                var name = reader.Name;
                var val = Convert.ToDouble(reader.ReadElementContentAsString());
                Values.Add(name, val);
            }
            else
            {
                reader.Skip();
            }
        } while (reader.Name != "week");
        if (reader.NodeType == XmlNodeType.EndElement)
        {
            reader.ReadEndElement();
        }
    }

我工作正常。 这个解决方案没有使用XElement和Linq,@ Volkan Paksoy提供了使用XElement的方法,这个方法更容易理解

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM