在嵌套属性上使用XmlAttributeOverrides

我正在尝试使用XmlAttributeOverrides来控制在序列化类之后哪些类属性出现在xml中。 它适用于“根”类上的属性,但不适用于嵌套属性。 这是一个简单的例子来说明我想要完成的事情。

我的类层次结构如下:

public class Main { public string Name { get; set; } public Location Address { get; set; } } public class Location { public string StreetAddress { get; set; } public Contact ContactInfo{ get; set; } } public class Contact { public string PhoneNumber { get; set; } public string EmailAddr { get; set; } } 

当我序列化Main()时,我得到这样的东西:

   

我能做的是通过使用以下方式保持名称或地址出现:

 XmlAttributeOverrides overrides = new XmlAttributeOverrides(); XmlAttributes attribs = new XmlAttributes(); attribs.XmlIgnore = true; attribs.XmlElements.Add(new XmlElementAttribute("Address")); overrides.Add(typeof(Main), "Address", attribs); xs = new XmlSerializer(typeof(Main), overrides); 

我还需要做的是保持Main.Address.ContactInfo被序列化SOMETIMES (如果它是空的)。 我尝试了以下但是它们不起作用:

 XmlAttributeOverrides overrides = new XmlAttributeOverrides(); XmlAttributes attribs = new XmlAttributes(); attribs.XmlIgnore = true; attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo ")); overrides.Add(typeof(Contact), "ContactInfo ", attribs); xs = new XmlSerializer(typeof(Contact), overrides); 

和…

 XmlAttributeOverrides overrides = new XmlAttributeOverrides(); XmlAttributes attribs = new XmlAttributes(); attribs.XmlIgnore = true; attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo ")); overrides.Add(typeof(Main.Address.ContactInfo), "ContactInfo ", attribs); xs = new XmlSerializer(typeof(Main.Address.ContactInfo), overrides); 

我实际上已经尝试了很多,包括使用XPath语句来指定要定位的属性名称,但是不想在尝试失败的情况下填充此页面。 我用这种方法甚至可以问这个问题吗?

有更简单的方法来实现您正在寻找的东西。

您说如果ContactInfo包含任何数据,那么您要实现的是不要序列化/Main/Address/ContactInfo

如果保留代码,它将序列化所有Main的属性,无论它们是null还是空。 第一步,您需要向所有对象添加XmlSerializerNamespaces属性,否则每个空对象将被序列化为 。 这可以很容易地完成,如下:

 public MyXmlElement { public MyXmlElement() { // Add your own default namespace to your type to prevet xsi:* and xsd:* // attributes from being generated. this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] { new XmlQualifiedName(string.Empty, "urn:myDefaultNamespace") }); } [XmlElement("MyNullableProperty", IsNullable=false)] public string MyNullableProperty { get { return string.IsNullOrWhiteSpace(this._myNullableProperty) ? null : this._myNullableProperty; } set { this._myNullableProperty = value; } } [XmlNamespacesDeclaration] public XmlSerializerNamespaces Namespaces { get { return this._namespaces; } } private XmlSerializerNamespaces _namespaces; } 

上面的代码声明了一个Namespaces属性,该属性包含XML对象的所有相关名称空间。 您应该为所有对象提供默认命名空间(以上面的代码为模型)。 这可以防止在序列化对象时输出xsi:*xsd:*属性。 另外,使用System.Xml.Serialization.XmlElementAttribute指定该元素不可为空。

此外,通过检查string.IsNullOrWhiteSpace(someVariable)并返回null,那么在完成上述操作后,属性将不会被序列化。

所以,将这一切放在一起为您的Location类:

 public class Location { // You should have a public default constructor on all types for (de)sereialization. public Location() { this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] { new XmlQualifiedName(string.Empty, "urn:myNamespace"); // Default namespace -- prevents xsi:nil="true" from being generated, as well as xsd:* attributes. }); } public string StreetAddress { // If you don't want  to be generated, do this: get { return string.IsNullOrEmpty(this._streetAddress) ? null : this._streetAddress; } // Otherwise, if you don't care, just do // get; // Only need to implement setter if you don't want xsi:nil="true" to be generated. set { this._streetAddress = value; } // Otherwise, just // set; } private string _streetAddress; [XmlElement("ContactInfo", IsNullable=false)] public Contact ContactInfo { // You must definitely do this to prevent the output of ContactInfo element // when it's null (ie contains no data) get { if (this._contactInfo != null && string.IsNullOrWhiteSpace(this._contactInfo.PhoneNumber) && string.IsNullOrWhiteSpace(this._contactInfo.EmailAddr)) return null; return this._contactInfo; } set { this._contactInfo = value; } } private Contact _contactInfo; [XmlNamespacesDeclarations] public XmlSerializerNamespaces Namespaces { get { return this._namespaces; } } private XmlSerializerNamespaces _namespaces; } 

通过对Location类的这些更改,当没有属性为null,空或空格,或者ContactInfo本身为null时,不应再将空的ContactInfo属性序列化为XML。

您应该对其他对象进行类似的更改。

有关.NET XML序列化的更多信息,请参阅我的其他stackoverflow答案:

  • XmlSerializer:删除不必要的xsi和xsd名称空间
  • 在.NET中序列化对象时省略所有xsi和xsd命名空间?
  • 抑制xsi:nil但在.Net中序列化时仍然显示空元素

对于其他试图使用XmlAttributeOverrides执行此操作的人,事实certificate@ user1437872非常接近于找到答案。 这是覆盖嵌套元素ContactInfo的覆盖代码。

 XmlAttributeOverrides overrides = new XmlAttributeOverrides(); XmlAttributes attribs = new XmlAttributes(); attribs.XmlIgnore = true; attribs.XmlElements.Add(new XmlElementAttribute("ContactInfo")); overrides.Add(typeof(Address), "ContactInfo ", attribs); xs = new XmlSerializer(typeof(Main), overrides);