158

When using a standard .NET Xml Serializer, is there any way I can hide all null values? The below is an example of the output of my class. I don't want to output the nullable integers if they are set to null.

Current Xml output:

<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myNullableInt p2:nil="true" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
   <myOtherInt>-1</myOtherInt>
</myClass>

What I want:

<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myOtherInt>-1</myOtherInt>
</myClass>
Timwi
  • 65,159
  • 33
  • 165
  • 230
GuruMeditation
  • 1,852
  • 4
  • 16
  • 14

7 Answers7

293

You can create a function with the pattern ShouldSerialize{PropertyName} which tells the XmlSerializer if it should serialize the member or not.

For example, if your class property is called MyNullableInt you could have

public bool ShouldSerializeMyNullableInt() 
{
  return MyNullableInt.HasValue;
}

Here is a full sample

public class Person
{
  public string Name {get;set;}
  public int? Age {get;set;}
  public bool ShouldSerializeAge()
  {
    return Age.HasValue;
  }
}

Serialized with the following code

Person thePerson = new Person(){Name="Chris"};
XmlSerializer xs = new XmlSerializer(typeof(Person));
StringWriter sw = new StringWriter();
xs.Serialize(sw, thePerson);

Results in the followng XML - Notice there is no Age

<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>
Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
  • 14
    One word: Awesome! [MSDN ShouldSerialize](http://msdn.microsoft.com/en-us/library/53b8022e(VS.71).aspx) – scheien Feb 27 '13 at 09:24
  • 11
    The ShouldSerialize pattern does only work, if the property is not marked with an XmlAttribute-attribute (I thought this should work, because an attribute could be optional, but it does not). – Matze Apr 30 '13 at 11:43
  • @Matze interesting, I have not tried that. I would also have assumed it would work. – Chris Taylor Apr 30 '13 at 19:33
  • @ChrisTaylor Yes; I assumed the same. The tricky thing was that the creation of the XmlSerializer instance failed (due to an error when reflecting the type) until I removed the XmlAttribute from the nullable int-property. – Matze May 03 '13 at 11:52
  • if all the properties are null any idea how to remove the xml root element also? – neel shah Sep 11 '15 at 14:20
  • How to apply it to elements in list. I have list of elements and I would like to not emit elements that have some property null. – Hooch Jan 21 '16 at 14:37
  • @Hooch, you can apply the following attribute to the list[XmlArrayItem(IsNullable= false)]. This indicates that null items in the list should not be serialized. – Chris Taylor Jan 23 '16 at 06:04
  • @ChrisTaylor Problem is that those element are not null. Lets say that I want to ignore Null or Empty or Whitespace Strings. – Hooch Jan 23 '16 at 14:15
  • @Hooch, if you create a stackoverflow with a question including an example, I or someone else could potentially provide a more specific solution. However, by the sound of things, you will probably need to implement IXmlSerializable and control which items are written based on the your criterial. If your array items are classes then you can implement the interface on that class rather than on the container class. Hope that helps. – Chris Taylor Jan 23 '16 at 16:44
  • Not very handy with many fields (3 lines of code to add for each...). Isn't there a way to apply that to all fields ? – Pierre de LESPINAY Sep 11 '17 at 16:51
  • 2
    @PierredeLESPINAY - From visual studio 2015 and up, you could use: public bool ShouldSerializeAge() => Age.HasValue; – RooiWillie Feb 21 '18 at 18:33
  • It looks like magic to me! I'm using it for nullable enums and worked like a charm. – Antonio Rodríguez Apr 22 '21 at 08:13
  • This should not be work for XmlAttribute, custom serializer will require this case. – Manu Aug 04 '21 at 14:09
  • Not working if the class has a constructor with parameters – Ejrr1085 Apr 02 '22 at 17:54
  • @Ejrr1085 - Can you provide more detail on your scenario? XmlSerialization requires a parameterless constructor, which is a requirement for the XmlSerializer not specific to the ability to exclude null fields. In addition to the parameterless constructor, you can have constructors with parameters and this still works. – Chris Taylor Apr 04 '22 at 13:13
  • @scheien this is not awesome. it's a maintenance nightmare – symbiont Jun 17 '22 at 09:15
  • @symbiont yeah it can be. Bear in mind that this is old tech. Worked like a charm for the use case I had back in the day. – scheien Jun 18 '22 at 12:18
40

Additionally to what Chris Taylor wrote: if you have something serialized as an attribute, you can have a property on your class named {PropertyName}Specified to control if it should be serialized. In code:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}
Daniel Rose
  • 17,233
  • 9
  • 65
  • 88
  • Be carefull, `{PropertyName}Specified` attributes have to be of type bool. – sinsedrix Dec 10 '12 at 08:32
  • 1
    Works also as a function. For example, if `MyValue` is `int?`, one could do `public bool MyValueSpecified => MyValue.HasValue;`. – OfirD Nov 01 '20 at 14:53
  • 2
    @OfirD `public bool MyValueSpecified => MyValue.HasValue;` is not function. It is getter only property. Same as: `public bool MyValueSpecified { get { return MyValue.HasValue; } }` – Gh61 May 03 '21 at 14:39
33

It exists a property called XmlElementAttribute.IsNullable

If the IsNullable property is set to true, the xsi:nil attribute is generated for class members that have been set to a null reference.

The following example shows a field with the XmlElementAttribute applied to it, and the IsNullable property set to false.

public class MyClass
{
   [XmlElement(IsNullable = false)]
   public string Group;
}

You can have a look to other XmlElementAttribute for changing names in serialization etc.

JPBlanc
  • 70,406
  • 17
  • 130
  • 175
  • 13
    Unfortunately, this only works for reference types, not for value types or their Nullable counterparts. – Vincent Sels May 27 '13 at 14:46
  • 3
    @VincentSels is correct. MSDN says: _You cannot apply the IsNullable property to a member typed as a value type because a value type cannot contain null. Additionally, you cannot set this property to false for nullable value types. When such types are null, they will be serialized by setting xsi:nil to true._ – bouvierr Oct 30 '14 at 13:25
15

You can define some default values and it prevents the fields from being serialized.

    [XmlElement, DefaultValue("")]
    string data;

    [XmlArray, DefaultValue(null)]
    List<string> data;
MichaelSo
  • 211
  • 2
  • 8
3

I prefer creating my own xml with no auto-generated tags. In this I can ignore creating the nodes with null values:

public static string ConvertToXML<T>(T objectToConvert)
    {
        XmlDocument doc = new XmlDocument();
        XmlNode root = doc.CreateNode(XmlNodeType.Element, objectToConvert.GetType().Name, string.Empty);
        doc.AppendChild(root);
        XmlNode childNode;

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        foreach (PropertyDescriptor prop in properties)
        {
            if (prop.GetValue(objectToConvert) != null)
            {
                childNode = doc.CreateNode(XmlNodeType.Element, prop.Name, string.Empty);
                childNode.InnerText = prop.GetValue(objectToConvert).ToString();
                root.AppendChild(childNode);
            }
        }            

        return doc.OuterXml;
    }
1

In my case the nullable variables/elements were all String type. So, I simply performed a check and assigned them string.Empty in case of NULL. This way I got rid of the unnecessary nil and xmlns attributes (p3:nil="true" xmlns:p3="http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty
Sagar
  • 579
  • 5
  • 7
  • 1
    This solutions very limited and only works with string. For other types empty string is still a value. Some parsers try to find attribute and if found try to convert the value to target type. For such parsers, missing attribute means null and if there is attribute then it must have a valid value. – ZafarYousafi Jul 16 '14 at 23:16
0
private static string ToXml(Person obj)
{
  XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
  namespaces.Add(string.Empty, string.Empty);

  string retval = null;
  if (obj != null)
  {
    StringBuilder sb = new StringBuilder();
    using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { OmitXmlDeclaration = true }))
    {
      new XmlSerializer(obj.GetType()).Serialize(writer, obj,namespaces);
    }
    retval = sb.ToString();
  }
  return retval;
}
Rauld
  • 980
  • 2
  • 10
  • 19