Deserialize Xml with empty elements

你。 提交于 2019-12-19 03:14:04

问题


Consider the following XML:

<a>
    <b>2</b>
    <c></c>
</a>  

I need to deserialize this xml to an object. So, i wrote the following class.

public class A
{
    [XmlElement("b", Namespace = "")]
    public int? B { get; set; }

    [XmlElement("c", Namespace = "")]
    public int? C { get; set; }

}

Since i'm using nullables, i was expecting that, when deserialing the above xml, i would get an object A with a null C property.

Instead of this, i get an exception telling the document has an error.


回答1:


There's a difference between a missing element and a null element.

A missing element, <a><b>2</b></a>. Here C would take whatever default value you specify, using the DefaultValue attribute, or null if there's no explicit default.

A null element <a><b>2</b><c xs:Nil='true'/></a>. Here you will get null.

When you do <a><b>2</b><c></c><a/> the xml serializer will try to parse string.Empty as an integer an will correctly fail.

Since your provider is generating invalid xml you will need to do this, if using the XmlSerializer:

[XmlRoot(ElementName = "a")]
public class A
{
    [XmlElement(ElementName = "b")]
    public int? B { get; set; }

    [XmlElement(ElementName = "c")]
    public string _c { get; set; }

    public int? C
    {
        get
        {
            int retval;

            return !string.IsNullOrWhiteSpace(_c) && int.TryParse(_c, out retval) ? (int?) retval : null;
        }
    }
}

or slightly better using the DataContractSerializer

[DataContract(Name="a")]
public class A1
{
    [DataMember(Name = "b")]
    public int? B { get; set; }

    [DataMember(Name = "c")]
    private string _c { get; set; }

    public int? C
    {
        get
        {
            int retval;

            return !string.IsNullOrWhiteSpace(_c) && int.TryParse(_c, out retval) ? (int?)retval : null;
        }
    }
}

although the DataContractSerializer doesn't support attributes if that's a problem.




回答2:


To deserialize empty tags like 'c' in your example:

    <foo>
        <b>2</b>
        <c></c>
    </foo>

I used this approach. First it removes the null or empty elements from the XML file using LINQ and then it deserialize the new document without the null or empty tags to the Foo class.

    public static Foo ReadXML(string file)
    {
            Foo foo = null;
            XDocument xdoc = XDocument.Load(file);
            xdoc.Descendants().Where(e => string.IsNullOrEmpty(e.Value)).Remove();

            XmlSerializer xmlSer = new XmlSerializer(typeof(Foo));
            using (var reader = xdoc.Root.CreateReader())
            {
                foo = (Foo)xmlSer.Deserialize(reader);
                reader.Close();
            }
            if (foo == null)
                foo = new Foo();

            return foo;
    }

Which will give you default values on the missing properties.

    foo.b = 2;
    foo.c = 0; //for example, if it's an integer

I joined information from this links:

Remove empty XML tags

Use XDocument as the source for XmlSerializer.Deserialize?



来源:https://stackoverflow.com/questions/9673030/deserialize-xml-with-empty-elements

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