Customizing IntermediateSerializer, part 1

Originally posted to Shawn Hargreaves Blog on MSDN, Tuesday, August 26, 2008

So, you are using IntermediateSerializer to import XML data into your content build process. Excellent!

Having read my previous post, you understand how to control the formatting of your XML via attributes. Even better!!

Lets say you want to serialize this data:

    class TestClass
{
public int elf = 23;
}

No problem, IntermediateSerializer can do that!!!

"But wait", I hear you cry. "It just so happens that today is a Tuesday, and on Tuesdays I like my elves to be serialized in base 16, not that boring default decimal format."

Oh. Hmm... There is no serializer attribute for specifying the number base. What a drag!!!!

This is a perfect place to apply the Serialization Helper Property pattern:

An example:

    class TestClass
{
[ContentSerializerIgnore]
public int elf = 23;


[ContentSerializer(ElementName = "elf")]
private string ElfSerializationHelper
{
get
{
return "0x" + elf.ToString("X8");
}

set
{
if (value.StartsWith("0x"))
value = value.Substring(2);

elf = int.Parse(value, NumberStyles.HexNumber);
}
}
}

This produces the following XML:

    <XnaContent>
<Asset Type="TestClass">
<elf>0x00000017</elf>
</Asset>
</XnaContent>

The helper property is private, so people using your class need never be aware of it, but IntermediateSerializer has no trouble including private properties as long as you decorate them with the necessary attributes.

The helper property shown above returns a string, but this can be any type you like. For more complicated formatting tasks, it can even return a temporary instance of a private helper class. For instance this version will split the number into three separate XML elements, dividing the value into hundreds, tens, and ones:

    class TestClass
{
[ContentSerializerIgnore]
public int elf = 23;


[ContentSerializer(ElementName = "elf")]
private DecimalSerializationHelper ElfSerializationHelper
{
get
{
DecimalSerializationHelper helper = new DecimalSerializationHelper();

helper.Hundreds = elf / 100;
helper.Tens = (elf / 10) % 10;
helper.Ones = elf % 10;

return helper;
}

set
{
elf = (value.Hundreds * 100) +
(value.Tens * 10) +
(value.Ones);
}
}


private class DecimalSerializationHelper
{
public int Hundreds;
public int Tens;
public int Ones;
}
}

Resulting XML:

    <XnaContent>
<Asset Type="TestClass">
<elf>
<Hundreds>0</Hundreds>
<Tens>2</Tens>
<Ones>3</Ones>
</elf>
</Asset>
</XnaContent>

I used this pattern inside the Content Pipeline itself, for a few of our more gnarly types that needed to be serialized in specific ways. It can also be useful to add special XML-only validation logic to the helper property setter.

Blog index   -   Back to my homepage