在定义为XmlElement的自闭合标记之后,XmlSerializer将null设置为property

时间:2018-06-08 08:39:49

标签: c# xml serialization xmlserializer

想象一下如下所示的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; }
}

由于某种原因,Baz被定义为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。如何配置XmlSerializer将自闭标记视为开 - 关对?在这两种情况下都应该对SuperImportant进行反序列化,但它不在前者中,这是错误的。

1 个答案:

答案 0 :(得分:1)

您应该将Baz标记为[XmlAnyElement("Baz")],如下所示:

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

docs中所述,此属性

  

指定成员(返回XmlElementXmlNode个对象数组的字段)包含表示在被序列化或反序列化的对象中没有相应成员的任何XML元素的对象。   
...
  您还可以将XmlAnyElementAttribute应用于返回单个XmlElement对象的字段。如果这样做,则必须使用XmlElement类的属性和方法递归迭代未知元素。

应用属性后,Baz属性将正确捕获<Baz/><Baz></Baz>元素,而不会干扰后续节点的反序列化。 [XmlElement("Baz")]导致您看到的不一致似乎很奇怪,但由于[XmlAnyElement("Baz")]旨在处理这种情况,因此应该使用它。

示例工作.Net小提琴here