Xml serialization - Hide null values
Asked Answered
I

7

159

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>
Importune answered 28/4, 2011 at 12:22 Comment(0)
F
296

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>
Forme answered 28/4, 2011 at 12:28 Comment(18)
One word: Awesome! MSDN ShouldSerializeIncrassate
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).Paradiddle
@Paradiddle interesting, I have not tried that. I would also have assumed it would work.Forme
@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.Paradiddle
if all the properties are null any idea how to remove the xml root element also?Millham
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.Confectionary
@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.Forme
@ChrisTaylor Problem is that those element are not null. Lets say that I want to ignore Null or Empty or Whitespace Strings.Confectionary
@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.Forme
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 ?Neel
@PierredeLESPINAY - From visual studio 2015 and up, you could use: public bool ShouldSerializeAge() => Age.HasValue;Messene
It looks like magic to me! I'm using it for nullable enums and worked like a charm.Erdmann
This should not be work for XmlAttribute, custom serializer will require this case.Purgatory
Not working if the class has a constructor with parametersWitchhunt
@Witchhunt - 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.Forme
@Incrassate this is not awesome. it's a maintenance nightmareWilton
@Wilton 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.Incrassate
The only documentation I could find was for Forms, but that states that the ShouldSerialize method should be private. I only got this to work on .NET 4.7.2 (also for nullable value types) when setting the method to public. The XmlElementAttribute could remain in use.Brendin
R
42

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;
}
Renown answered 28/4, 2011 at 12:48 Comment(3)
Be carefull, {PropertyName}Specified attributes have to be of type bool.Firebug
Works also as a function. For example, if MyValue is int?, one could do public bool MyValueSpecified => MyValue.HasValue;.Garfish
@Garfish public bool MyValueSpecified => MyValue.HasValue; is not function. It is getter only property. Same as: public bool MyValueSpecified { get { return MyValue.HasValue; } }Local
I
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.

Isidroisinglass answered 28/4, 2011 at 12:43 Comment(2)
Unfortunately, this only works for reference types, not for value types or their Nullable counterparts.Chrysalid
@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.Mumps
V
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;
Venita answered 15/12, 2013 at 19:9 Comment(1)
Unfortunately, this does not work for nullable value typesByway
A
4

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;
    }
Allowance answered 10/6, 2016 at 20:46 Comment(0)
K
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
Kaffraria answered 7/5, 2014 at 13:59 Comment(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.Boylston
A
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;
}
Amari answered 18/10, 2012 at 10:40 Comment(1)
That only removes the specifications on the Root, but then you get extra specifications fer each and every NULL value on nullable reference types...Dannettedanni

© 2022 - 2024 — McMap. All rights reserved.