XmlSerializer устанавливает значение null для свойства после самозакрывающегося тега, определенного как XmlElement - PullRequest
0 голосов
/ 08 июня 2018

Представьте, что у вас есть XML-структура, подобная следующей:

[XmlRoot("Foo")]
public class Foo
{
    [XmlElement("Bar")]
    public Bar Bar { get; set; }
    [XmlElement("SuperImportant")]
    public SuperImportant SuperImportant { get; set; }
}

[XmlRoot("Bar")]
public class Bar
{
    [XmlElement("Baz")]
    public XmlElement Baz { get; set; }
}

[XmlRoot("SuperImportant")]
public class SuperImportant
{
    [XmlElement("MegaImportant")]
    public string MegaImportant { get; set; }
}

База определена как XmlElement по некоторым причинам.

Теперь проверьте этот код:

var template = @"
<Foo>
  <Bar>
    {0}
  </Bar>
  <SuperImportant>
    <MegaImportant>42</MegaImportant>
  </SuperImportant>
</Foo>";

var selfClosed = new StringReader(String.Format(template, "<Baz/>"));    

var openClosePair = new StringReader(String.Format(template, "<Baz></Baz>"));

XmlSerializer xmlSerializer = new XmlSerializer(typeof(Foo));

var o1 = (Foo)xmlSerializer.Deserialize(selfClosed);
Console.WriteLine(o1.SuperImportant == null); // True, it's not there

var o2 = (Foo)xmlSerializer.Deserialize(openClosePair);
Console.WriteLine(o2.SuperImportant == null); // False, it's there

Как вы можете видеть, если какой-либо тег, определенный как XmlElement в определении класса, кажется самозакрывающимся, элемент сразу после родительского тега имеет значение null ed.Как я могу настроить XmlSerializer для обработки самозакрывающихся тегов как пар открытого-закрытого типа?SuperImportant следует десериализовать в обоих случаях, но не в первом, что неправильно.

1 Ответ

0 голосов
/ 08 июня 2018

Вы должны пометить свойство Baz с помощью [XmlAnyElement("Baz")] следующим образом:

[XmlRoot("Bar")]
public class Bar
{
    [XmlAnyElement("Baz")]
    public XmlElement Baz { get; set; }
}

Как объяснено в документах , этот атрибут

Указывает, что член (поле, которое возвращает массив объектов XmlElement или XmlNode ) содержит объекты, представляющие любой элемент XML, который не имеет соответствующего члена в сериализуемом или десериализованном объекте.
...
Вы также можете применить XmlAnyElementAttribute к полю, которое возвращает один XmlElement объект.Если вы это сделаете, вы должны будете использовать свойства и методы класса XmlElement для рекурсивной итерации по неизвестным элементам.

После применения атрибута свойство Baz будет правильно захватывать оба <Baz/> и <Baz></Baz> элементов без вмешательства в десериализацию последующих узлов.Кажется странным, что [XmlElement("Baz")] вызывает несоответствие, которое вы видите, но, поскольку [XmlAnyElement("Baz")] предназначен для обработки этой ситуации, его следует использовать вместо этого.

Пример работающей .Net fiddle здесь .

...