
Formatting XML When Serializing C# Objects
Serializing your custom objects in C# is quite simple, and there are several powerful tools at your disposal for crafting the exact XML object you need. Let’s take a look at a few of the ways we can harness the power of C#’s built-in XmlSerializer
.
Setting Up Your Classes
Let’s see how to set up a custom Person
object for XML serialization. We can start with a basic outline for our object:
XmlElement
The names of the object properties and XML properties may not always match. Let’s assume that we need Person.FirstName
to serialize to <First>
and Person.LastName
to serialize to <Last>
. To achieve this, we need to use the XmlElement
attribute.
Now that this attribute has been set up, XmlSerializer
will know how to label the FirstName
and LastName
properties of any Person
object it receives. XmlElement
also contains an IsNullable
property. Let’s assume that Person.Email
is nullable and add the appropriate attribute.
We are now able to have a Person
with a null value in the Email
property and it will still be included in the structure of the XML.
ShouldSerialize
While IsNullable
is a quick and easy way to handle nullability, sometimes we may want more granular control over whether to include a property at all. In this case, the ShouldSerialize
method will help us out. Let’s assume that if our person is under the age of 18, we don’t want to include <Age>
in our XML whatsoever. To accomplish this, we add a ShouldSerializeAge
method to our Person
class.
With this addition, the <Age>
property in our XML will be completely removed if the person is under 18. This method will work with any property, and will be named using the ShouldSerialize[C# Property Name]
convention.
XmlText
Now let’s take a look at our custom PhoneNumber
. In our C# definition, we have separated the area code from the last seven digits of each phone number, but we assume that our XML should display each phone number as a whole, formatted number. To accomplish this, we can use [XmlIgnore]
and [XmlText]
in our definition.
Here, the XmlIgnore
tells the serializer to not include either of the two properties when serializing. XmlText
allows us to set a custom FormattedNumber
property, which combines our two values into a single string, which will be serialized as the string value of the entire PhoneNumber
object.
XmlSerializer
Now that we have our object set up to be serialized, let’s actually use the built-in C# serializer to get our XML. Setting up a serializer is simple; we just need to provide the serializer with the object type (Person
) and use a StringWriter
to print our XML results.
Usage Examples
Now that everything is set up, let’s try a few examples that showcase the power of XmlSerializer
.
Example 1 (Happy Path)
In our first example, we have a basic Person
with no null properties and an age greater than 18.
Using our serializer, we get the following XML:
A few things to note on this first example are the <First>
and <Last>
tags that we set up using [XmlElement(ElementName)]
, as well as the PhoneNumber
serializing to a single string that combines the two properties of our object.
Example 2 (Email is null)
Now, let’s see what happens when Email
is set to null.
Using our serializer, we get the following XML:
Notice how the <Email>
property still exists in the XML but contains no value. This is how IsNullable
handles null property values.
Example 3 (Age < 18)
For our final example, let’s look at how our ShouldSerializeAge
method handles a Person
under the age of 18.
Using our serializer, we get the following XML:
Other Serialization Options
These examples show off a few of the many ways to control your object serialization in C#, but I wanted to include two more ways to customize the XML.
Custom Namespaces
As you may have noticed, XmlSerializer
includes two xmlns namespaces in the serialized object by default. While this can sometimes be ignored, if your XML needs to match a particular template, you may need to remove or edit these namespaces. To do this, we will add a namespaces parameter when we call Serialize()
.
IMPORTANT: The following code is “not supported” per Microsoft, but works as intended to clear namespaces.
Setting the namespaces to empty in this way gives us the following XML when using the object from Example 1.
UTF-8 Encoding
XmlSerializer
uses UTF-16 encoding by default. To use UTF-8 encoding, we must set up a custom StringWriter
.
Combined with our updated namespaces, this gives us clean, UTF-8 encoded XML:
Using these methods, you can more granularly control how your custom objects are serialized into XML. Whether you need to match formatting for a request, store specific data, or simply want to display your object in a more readable fashion, XMLSerializer
can help you ensure your data is both accessible and well-structured.