Deserializing XML in C# where a property could be either an attribute or an element

北城以北 提交于 2019-12-12 03:54:27

问题


I'm writing a C# library that, as one of its functions, needs to be able to accept XML of the following forms from a web service and deserialize them.

Form 1:

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

Form 2:

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

Here's my class that I'm deserializing to:

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
    {
       ...
    }
}

The problem is that in one XML sample, the name attribute of the Sample element is an element, and in the other it's an attribute. If I decorate the property of my class with both XmlAttribute and XmlElement, I get an exception thrown when creating an instance of XmlSerializer.

I've been googling for a good while now, and I can't find any docs that deal with this situation. I assume, but don't know for sure, that this is because when creating an XML schema, you're not supposed to use the same name for an attribute and a child element of the same element.

So, what do I do here?

One solution might be to have two totally separate models for the different types. That would probably work, but doesn't seem very elegant.

Another option might be to implement IXmlSerializable and write some elaborate code to handle this in the deserialize method. That would be an awfully verbose solution to a simple problem.

Third option I'm hoping for: some way of applying both XmlAttribute and XmlElement to the same property, or an equivalent "either-or" attribute.

Fourth option: Change the web service the XML comes from to use one form consistently. Unfortunately, the folks who own it may not be willing to do this.


回答1:


Specify only one attribute to Name property. This will correctly parse out the first xml form.

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

To parse the second xml form, subscribe the XmlSerializer to the UnknownAttribute event.

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

In the event handler, we get the desired value.

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


来源:https://stackoverflow.com/questions/41133429/deserializing-xml-in-c-sharp-where-a-property-could-be-either-an-attribute-or-an

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!