Using XmlAttributeOverrides on Nested Properties

旧巷老猫 提交于 2019-12-04 15:53:32
fourpastmidnight

There are easier ways to achieve what you're looking for.

You said that what you are trying to achieve is to not serialize /Main/Address/ContactInfo if ContactInfo contains no data.

If you leave your code as is, it will serialize all of Main's properties, whether they are null or empty or not. The first step, is you need to add a XmlSerializerNamespaces property to all of your objects or each empty object will be serialized as <myElement xsi:nil="true" />. This can be accomplished easily, as follows:

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

The code above declares a Namespaces property that holds all the relevant namespaces for the XML object. You should provide a default namespace for all of your objects (modeled after the code above). This prevents the xsi:* and xsd:* attributes from being output for your objects when they are serialized. Also, specify that the element is not nullable by using the System.Xml.Serialization.XmlElementAttribute.

Furthermore, by checking for string.IsNullOrWhiteSpace(someVariable) and returning null, then the property will not be serialized when the above has been done.

So, putting this all together for your Location class:

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 <StreetAddress xsi:nil="true" /> 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 (i.e. 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;
}

With these changes to your Location class, the empty ContactInfo property should no longer be serialized to XML when none of the properties are null, empty, or whitespace, or if ContactInfo itself is null.

You should make similar changes to your other objects.

See my other stackoverflow answers for more on .NET XML serialization:

For anyone else trying to do this with XmlAttributeOverrides, turns out that @user1437872 was very close to finding the answer. Here is the override code to ignore the nested element 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);

There is no need to add a ContactInfo element to the attribs

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
attribs.XmlIgnore = true;
overrides.Add(typeof(Address), "ContactInfo ", attribs);
xs = new XmlSerializer(typeof(Main), overrides);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!