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

我正在编写一个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)

2 years ago

仅为 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;
}