Десериализовать Xml с пустыми элементами - PullRequest
6 голосов
/ 12 марта 2012

Рассмотрим следующий XML:

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

Мне нужно десериализовать этот xml в объект.Итак, я написал следующий класс.

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

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

}

Поскольку я использую nullables, я ожидал, что при десериализации вышеупомянутого XML я получу объект A с нулевым свойством C.

Вместо этого яполучите исключение, сообщающее, что в документе есть ошибка.

Ответы [ 2 ]

8 голосов
/ 12 марта 2012

Существует разница между отсутствующим элементом и нулевым элементом.

Отсутствующий элемент, <a><b>2</b></a>. Здесь C будет принимать любое значение по умолчанию, которое вы укажете, используя атрибут DefaultValue , или NULL, если явного значения по умолчанию нет.

Нулевой элемент <a><b>2</b><c xs:Nil='true'/></a>. Здесь вы получите ноль.

Когда вы выполните <a><b>2</b><c></c><a/>, сериализатор xml попытается разобрать строку. Пустое число как целое число будет правильно завершено.

Поскольку ваш провайдер генерирует недействительный xml, вам нужно будет сделать это, если вы используете 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;
        }
    }
}

или чуть лучше с использованием 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;
        }
    }
}

хотя DataContractSerializer не поддерживает атрибуты, если это проблема.

2 голосов
/ 13 апреля 2017

Для десериализации пустых тегов, таких как 'c' в вашем примере:

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

Я использовал этот подход. Сначала он удаляет пустые или пустые элементы из файла XML с помощью LINQ, а затем десериализует новый документ без пустых или пустых тегов в классе Foo.

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

Что даст вам значения по умолчанию для отсутствующих свойств.

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

Я присоединился к информации по этим ссылкам :

Удалить пустые теги XML

Использовать XDocument в качестве источника для XmlSerializer.Deserialize?

...