Environmental Computing & Visualisation

XML serialization of optional value type element

Problem

The issue is how to implement a class structure that would properly serialize an optional value type element. Let us consider the following schema.

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="AthleteMedal" type="AthleteMedalType"/>

<xs:complexType name="AthleteMedalType">
  <xs:sequence>
   <xs:element name="Name" type="xs:string" minOccurs="1" maxOccurs="1"/>
   <xs:element name="Medal" type="MedalType" minOccurs="0" maxOccurs="1"/>
  </xs:sequence>
</xs:complexType>

<xs:simpleType name="MedalType">
 <xs:restriction base="xs:string">
  <xs:enumeration value="Gold" />
  <xs:enumeration value ="Silver" />
  <xs:enumeration value ="Bronze" />
 </xs:restriction>
</xs:simpleType>
</xs:schema>



This schema contains an element "MedalType". The element is optional minOccurs="0" so these are valid examples:

<?xml version="1.0"?>
<AthleteMedal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Mark</Name>
  <Medal>Silver</Medal>
</AthleteMedal>


<?xml version="1.0"?>
<AthleteMedal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Dan</Name>
</AthleteMedal>


The most natural class implementation of the medal option is through enumeration.

[System.SerializableAttribute()]
[System.Xml.Serialization.XmlRootAttribute("AthleteMedal", IsNullable = false)]
public partial class AthleteMedalType
{
  private string nameField;
  private MedalType medalField;
  public string Name
  {
    get { return this.nameField; }
    set { this.nameField = value; }
  }
  public MedalType Medal
  {
    get { return this.medalField; }
    set { this.medalField = value; }
  }
}
[System.SerializableAttribute()]
public enum MedalType
{
  Gold,
  Silver,
  Bronze,
}


However, there is a problem that a value type can not be null and is automatically initialized to 0. Serialization of the previous examples gives incorrect representation of object where Medal is not set:

<?xml version="1.0"?>
<AthleteMedal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Name>Mark</Name>
 <Medal>Silver</Medal>
</AthleteMedal>

<?xml version="1.0"?>
<AthleteMedal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Name>Dan</Name>
 <Medal>Gold</Medal>
</AthleteMedal>

First Attempt

My first attempt at solving this problem was to introduce NotApplicable element as in:

[System.SerializableAttribute()]
public enum MedalType
{
  [System.Xml.Serialization.XmlIgnoreAttribute()]
  NotApplicable = 0
  Gold,
  Silver,
  Bronze,
}


This is incorrect as XmlIgnoreAttribute cannot be applied to enumeration. Although this seems to be the most natural solution it would not propagate to other value types.

Second Attempt

My second attempt at solving this problem was to make medal a nullable element and add IsNullable=false attribute

[System.SerializableAttribute()]
[System.Xml.Serialization.XmlRootAttribute("AthleteMedal", IsNullable = false)]
public partial class AthleteMedalType
{
  private string nameField;
  private Nullable<MedalType> medalField;
  public string Name
  {
    get { return this.nameField; }
    set { this.nameField = value; }
  }
  [System.Xml.Serialization.XmlElementAttribute("IsNullable = false)]
  public MedalType Medal
  {
    get { return this.medalField; }
    set { this.medalField = value; }
  }
}

[System.SerializableAttribute()]
public enum MedalType
{
  Gold,
  Silver,
  Bronze,
}


This fails again because of design of the XmlElementAttribute see discussion at Microsoft Connect web site.

Solution or may be just workaround

The following example correctly treats serialization of this optional enumeration. The class code was generated using xsd utility .NET 4 and modified to set "MedalSpecfied" attribute to true.

Warning

  • It appears that this additional attribute is used by serialization but I have not seen it documented anywhere and I do not know if this feature will be supported in the future.
  • xsd does not generate medalFieldSpecified=true line within Set for Medal property. This needs to be added by hand. If medalFieldSpecified is left as false the Medal attribute is not serialized.
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlRootAttribute("AthleteMedal", IsNullable = false)]
public partial class AthleteMedalType
{
  private string nameField;
  private MedalType medalField;
  private bool medalFieldSpecified = false;
  public string Name
  {
    get { return this.nameField; }
    set { this.nameField = value; }
  }
  public MedalType Medal
  {
    get { return this.medalField; }
    set
    {
      this.medalField = value;
      medalFieldSpecified = true; // Manually modified. This line is not generated by xsd
    }
  }
  [System.Xml.Serialization.XmlIgnoreAttribute()]
  public bool MedalSpecified
  {
    get { return this.medalFieldSpecified; }
    set { this.medalFieldSpecified = value; }
  }
}
[System.SerializableAttribute()]
public enum MedalType
{
  Gold = 1, // Modified set to 1 to test automatic setting to default 0
  Silver = 2,
  Bronze = 3,
}

| home | services | projects | downloads | people
© 2011 Copyright EC&V Pty Ltd ABN 23 114 756 688