在C#中反序列化XML,其中属性可以是属性或元素

时间:2016-12-14 01:38:04

标签: c# xml xml-deserialization

我正在编写一个C#库,作为其功能之一,它需要能够从Web服务接受以下形式的XML并对其进行反序列化。

表格1:

<results>
  <sample>
    <status>status message</status>
    <name>sample name</name>
    <igsn>unique identifier for this sample</igsn>
  </sample>
</results>

表格2:

<results>
  <sample name="sample name">
    <valid code="InvalidSample">no</valid>
    <status>Not Saved</status>
    <error>error message</error> 
  </sample>
</results>

这是我正在反序列化的课程:

namespace MyNamespace
{
    [XmlRoot(ElementName = "results")]
    public class SampleSubmissionResponse
    {

        [XmlElement("sample")]
        public List<SampleSubmissionSampleResultRecord> SampleList { get; set; }

       ...
    }


    public class SampleSubmissionSampleResultRecord
    {
     ...

        /* RELEVANT PROPERTY RIGHT HERE */
        [XmlAttribute(Attribute = "name")]
        [XmlElement(ElementName = "name")]
        public string Name { get; set; }

      ...
    }

    public class SampleSubmissionValidRecord
    {
       ...
    }
}

问题在于,在一个XML示例中,Sample元素的name属性是一个元素,而另一个是属性。如果我用XmlAttribute和XmlElement装饰我的类的属性,我在创建XmlSerializer的实例时会抛出异常。

我现在一直在谷歌搜索,我找不到任何处理这种情况的文档。我假设,但不确定,这是因为在创建XML模式时,您不应该为同一元素的属性和子元素使用相同的名称。

那么,我该怎么办?

一种解决方案可能是为不同类型提供两个完全独立的模型。这可能会奏效,但似乎并不优雅。

另一种选择可能是实现IXmlSerializable并编写一些精心设计的代码来在deserialize方法中处理它。对于一个简单的问题,这将是一个非常冗长的解决方案。

我希望的第三个选项:某种方式将XmlAttribute和XmlElement应用于同一属性,或等效的“或 - 或”属性。

第四个选项:更改XML来自的Web服务以始终使用一个表单。不幸的是,拥有它的人可能不愿意这样做。

1 个答案:

答案 0 :(得分:0)

仅为Name属性指定一个属性。这将正确解析出第一个xml表单。

public class SampleSubmissionSampleResultRecord
{
    [XmlElement(ElementName = "name")]
    public string Name { get; set; }
}

要解析第二个xml表单,请将XmlSerializer订阅到UnknownAttribute个事件。

var xs = new XmlSerializer(typeof(SampleSubmissionResponse));
xs.UnknownAttribute += Xs_UnknownAttribute;

在事件处理程序中,我们得到所需的值。

private void Xs_UnknownAttribute(object sender, XmlAttributeEventArgs e)
{
    var record = (SampleSubmissionSampleResultRecord)e.ObjectBeingDeserialized;
    record.Name = e.Attr.Value;
}