使用DataContractSerializer反序列化xml的问题

时间:2016-01-12 07:53:39

标签: c# xml xsd

我有一个xml文件存储有关测试的详细信息

<TestUnit>
  <DataDetails>
     <Chart>
      ...............
     </Chart>    
  </DataDetails>
</TestUnit>

此xml先前已配置且已部署。 现在要求在datadetails中添加新的扩展图表节点,这是图表元素的数组。我们已相应地更新了架构,但在验证以前创建的XML时遇到错误,因为它没有在架构中添加新节点。

新XML看起来像

<TestUnit>
 <DataDetails>
   <Chart>
      ...............
   </Chart>    
   <ExtendedChart>
   </ExtendedChart>
 </DataDetails>
</TestUnit>

对于新创建的XML模式工作正常,但对于以前添加的XML,它不起作用。 投掷例外 捕获到System.Runtime.Serialization.SerializationException   的HResult = -2146233076   消息=第1行位置38724中的错误。不期望来自命名空间“http://schemas.datacontract.org/2004/07/TestDataObjects”的“元素”'filesField'。期待元素'extendedChartField'。

2 个答案:

答案 0 :(得分:0)

如果您的XML有不同的布局,我建议您实现ISerializable接口。通过实现它,您将不得不对序列化和反序列化进行编码,但这并不困难。您只需将条件序列化放在不常用的字段上。

如果需要,请随时提出帮助。

迪米特里。

答案 1 :(得分:0)

正如我的评论中所说,这是因为DataContractSerializer期望按字母顺序排列相同级别的元素。 请查看有关数据合同版本控制的this article on MSDN

如上所述,可以设置EmitDefaultValue=false,如果提供了默认值(通常为null或0),它将告诉DataContractSerializer不输出元素,但正如文章中提到的,这不是推荐使用。

相反,使用本文中提到的示例,您可以创建两个不同的类 - 每个版本一个,为Name的{​​{1}}属性添加公共值,如下所示:

DataContractAttribute
  

版本2端点可以成功将数据发送到版本1端点。序列化Car数据协定的第2版会产生类似于以下内容的XML。

// Version 1 of a data contract, on machine V1.
[DataContract(Name = "Car")]
public class CarV1
{
    [DataMember]
    private string Model;
}

// Version 2 of the same data contract, on machine V2.
[DataContract(Name = "Car")]
public class CarV2
{
    [DataMember]
    private string Model;

    [DataMember]
    private int HorsePower;
}
  

V1上的反序列化引擎找不到HorsePower字段的匹配数据成员,并丢弃该数据。

为了向后兼容:

  

版本1端点可以将数据发送到版本2端点。序列化Car数据协定的第1版会产生类似于以下内容的XML。

<Car>
    <Model>Porsche</Model>
    <HorsePower>300</HorsePower>
</Car>
  

版本2反序列化器不知道将HorsePower字段设置为什么,因为传入的XML中没有匹配的数据。 相反,该字段设置为默认值0。

在这个例子中,我们使用两个不同的类,因此它们都可以在同一范围内引用。在实践中,这些可能是同一个类,但版本之间略有不同。