Let's begin from the lowest class in the hierarchy:
[Serializable]
public class DimensionInfo
{
[XmlElement("enabled")]
public Boolean Enabled { get; set; }
public DimensionInfo()
{
}
}
As you see, there's nothing special here. Then, proceed with the next:
[Serializable]
public class Entry
{
private DimensionInfo _dimensionInfo = default(DimensionInfo);
private Boolean _containsDimensionInfo = true;
[XmlAttribute("key")]
public String Key { get; set; }
[XmlText(typeof(String))]
public String ContainsDimensionInfo
{
get
{
return CheckDimensionContaining().ToString().ToLower();
}
set
{
_containsDimensionInfo = Boolean.Parse(value);
}
}
[XmlIgnore]
public Boolean ContainsDimensionInfoSpecified
{
get { return !CheckDimensionContaining(); }
}
[XmlElement("dimensionInfo")]
public DimensionInfo DimensionInfo
{
get { return _dimensionInfo; }
set { _dimensionInfo = value; }
}
[XmlIgnore]
public Boolean DimensionInfoSpecified
{
get { return CheckDimensionContaining(); }
}
public Entry()
{
Key = String.Empty;
CheckDimensionContaining();
}
private Boolean CheckDimensionContaining()
{
return _containsDimensionInfo = _dimensionInfo != default(DimensionInfo);
}
}
Here the magic begins. With using selective XmlIgnoreAttribute
we can decide the ways the object serializes. The main class only wraps a list of Entries:
[Serializable]
[XmlRoot("metadata")]
public class Metadata
{
[XmlElement("entry")]
public List<Entry> Entries { get; set; }
public Metadata()
{
Entries = new List<Entry>();
}
}
How it is made: entry contains dimensionInfo if it exists, and false if it does not. Try out the code sample in console:
Metadata metadata = new Metadata();
metadata.Entries.Add(new Entry()); //Adding empty entry
//Adding entry with info
metadata.Entries.Add(new Entry() { DimensionInfo = new DimensionInfo() });
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Metadata));
using (FileStream fileStream = new FileStream("info.txt", FileMode.Create))
{
xmlSerializer.Serialize(fileStream, metadata);
}
It gave me the following output:
<metadata>
<entry key="">false</entry>
<entry key="">
<dimensionInfo>
<enabled>false</enabled>
</dimensionInfo>
</entry>
</metadata>
However, this code is not perfect and there's a lot of things to improve, but now you have an idea of how it works