5

I have a class which is used for Xml Serialization.

Inside which I have a nullable property which is decorated with XmlAttribute:

 [XmlAttribute("lastUpdated")]
 public DateTime? LastUpdated { get; set; }

How to ignore the property from serialization if it is null or empty?

I've tried the below but it doesn't serialize when there is a value (always ignores):

  [XmlIgnore]
        public DateTime? LastUpdatedValue { get; set; }

        [XmlAttribute("lastUpdated")]
       public DateTime LastUpdated { get; set; }

        public bool ShouldSerializeLastUpdated()
        {
            return LastUpdatedValue.HasValue;
        }
The Light
  • 26,341
  • 62
  • 176
  • 258
  • 5
    Have you seen this http://stackoverflow.com/questions/244953/serialize-a-nullable-int?rq=1 – Yahya Apr 23 '13 at 14:56
  • What do you expect the XML to look like? In this case you'll get `` if the property is null; you could either post-process your xml (easier) or you can write a XmlWriter class (harder, performs better). There are other options that are both hard and bloat your code. – Sten Petrov Apr 23 '13 at 14:57
  • no I just want to ignore the xmlattribute if it's null. but DateTime? is not serializable. How to replace it? – The Light Apr 23 '13 at 15:09

5 Answers5

11

Nullable is not directly supported by XmlSerialization.

If you want use a nullable property you must use a non nullable property and add a boolean property with the same name of property with the suffix "Specified" which specifie when the property must be serializable.

An example with your case :

    private DateTime? _lastUpdated;

    [XmlAttribute("lastUpdated")]
    public DateTime LastUpdated {
        get {
            return (DateTime)_lastUpdated;
        }
        set
        {
            _lastUpdated = value;
        }
    }

    public bool LastUpdatedSpecified
    {
        get
        {
            return _lastUpdated.HasValue;
        }
    }
binard
  • 1,726
  • 1
  • 17
  • 27
5

I know this topic is old. This is the solution I came with. A class which encapsulates the type, and has implicit casting to the type. When serializing, the member variable can be marked with IsNullable = false without getting compiler errors, and blocking it from being serialized when null.

public class Optional<T> where T : struct, IComparable
{
    public Optional(T valueObject)
    {
        Value = valueObject;
    }

    public Optional()
    {
    }

    [XmlText]
    public T Value { get; set; }

    public static implicit operator T(Optional<T> objectToCast)
    {
        return objectToCast.Value;
    }

    public static implicit operator Optional<T>(T objectToCast)
    {
        return new Optional<T>(objectToCast);
    }
}

Then use it in your class

[Serializable]
[XmlRoot(ElementName = "foo")]
public class foo
{
   [XmlElement(ElementName = "myInteger", isNullable = false)]
   Optional<int> myInt;
}

You can do things like

        myFoo.myInt = 7;
        int j = 8 + myFoo.myInt;

For all purposes it's an int. For serialization purposes, it can be null and blocked from being serialized.

DDRider62
  • 753
  • 6
  • 17
  • 1
    Thank you, this worked fine for me! When using it with another custom datatype (my bools need to be serialized as Y/N), I've changed the IComparable to IComparable, where I could implement IComparable in my CustomBool type – BerDev Dec 05 '18 at 11:01
  • This doesn't work for [XmlElement(DataType="date")]. 'date' is an invalid value for the XmlElementAttribute.DataType property. The property may only be specified for primitive types. – JJS Jan 30 '21 at 22:33
4

This is working for me.

    [XmlIgnore]
    public float? Speed { get; set; }

    [XmlAttribute("Speed")]
    public float SpeedSerializable
    {
        get
        {
            return this.Speed.Value;
        }
        set { this.Speed = value; }
    }

    public bool ShouldSerializeSpeedSerializable()
    {
          return Speed.HasValue;
    }
2

Note: This works for sure in SOAP contracts in WCF. I haven't tested in other Xml serialization scenarios.

When using a [DataContract] you can use

[DataMember(EmitDefaultValue = false)]

  • For a boolean it will only emit the value if it is true.
  • For a nullable boolean it will only emit if it is not null.
  • For a string it will only emit the value if it isn't null.
  • For an int it will only emit the value if it isn't 0.

etc.

Make sure to put [DataContract] on the class itself and [DataMember] on all members you want serialized, whether you're specifying EmitDefaultValue or not.

Setting the EmitDefaultValue property to false is not a recommended practice. It should only be done if there is a specific need to do so (such as for interoperability or to reduce data size).

https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute.emitdefaultvalue(v=vs.110).aspx

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
1

You can use XmlElementAttribute.IsNullable:

[Serializable]
public class Result
{
    [XmlElement(IsNullable = true)]
    public DateTime? LastUpdated  { get; set; }
}
Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
  • It could not be used with attributes. It is only used fo elements. – Belurd Apr 05 '16 at 09:44
  • This does the opposite of what was asked. From [the documentation](https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlelementattribute.isnullable): "Gets or sets a value that indicates whether the XmlSerializer must serialize a member that is set to null as an empty tag with the xsi:nil attribute set to true." – Simon Morgan Mar 17 '23 at 09:15