I am writing a reporting tool and I got the required schema as a set of xsd files. Open the Visual Studio command line and run xsd.exe on the outer schema specifying /c to build classes. I get this nice 12k line code file. Ok so this is going to be a breeze right?
Ok so I pop into a C# project place my generated source file and start populating objects as a test. I serialize to a xml file and it looks pretty good. Then I notice the BeginDate field is missing. Lets take a look at the generated code. That’s weird look at that BeginDateSpecified boolean property.. Hmmm. That’s a funny way of doing things. Lets take a look at the xsd for this element.
[System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
public System.DateTime BeginDate{
get { return this.BeginDateField;}
set { this.BeginDateField = value;}
}
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool BeginDateSpecified{
get { return this.BeginDateFieldSpecified;}
set { this.BeginDateFieldSpecified = value;}
}
<xsd:element name="BeginDate" type="DateType" minOccurs="0"/>
No mention of “BeginDateSpecified” in the xsd file. Ok I will play along.
NameSpecified = true;
I run the XmlSerializer again and now the field is there.
Ok so for every element that has the attribute minOccurs=”0″ in the xsd I am going to have to tell the serializer whether or not it has a value? That won’t do.
Let’s see what we can do.
[System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
public System.DateTime? BeginDate{
get { return this.BeginDateField;}
set { this.BeginDateField = value;}
}
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool BeginDateSpecified{
get { return this.BeginDate != null;}
}
Ok so if the property is persisted as an element we can change it to a nullable type and then in the BeginDateSpecified property can just check for null.
We can use this regex to search
(?^[^\S\r\n]*public[^\S\r\n])(?(System\.)*\w*)[^\S\r\n](?\w*)(?\r?\n[^\S\r\n]*{\r?\n[^\S\r\n]*get\r?\n[^\S\r\n]*{\r?\n[^\S\r\n]*return[^\S\r\n]this.\w*;\r?\n[^\S\r\n]*}\r?\n[^\S\r\n]*set\r?\n[^\S\r\n]*{\r?\n[^\S\r\n]*this.\w*[^\S\r\n]=[^\S\r\n]value;\r?\n[^\S\r\n]*}\r?\n[^\S\r\n]*}\r?\n\r?\n[^\S\r\n]*///[^\S\r\n]\\r?\n[^\S\r\n]*\[System\.Xml\.Serialization\.XmlIgnoreAttribute\(\)\]\r?\n[^\S\r\n]*public[^\S\r\n]bool[^\S\r\n]\w*Specified\r?\n[^\S\r\n]*{\r?\n[^\S\r\n]*get\r\n[^\S\r\n]*{\r?\n[^\S\r\n]*return[^\S\r\n]this.)\w*(?;\r?\n[^\S\r\n]*}\r?\n)[^\S\r\n]*set\r?\n[^\S\r\n]*{\r?\n[^\S\r\n]*this.\w*[^\S\r\n]=[^\S\r\n]value;\r?\n[^\S\r\n]*}\r?\n
(if you copy this be aware there should be no spaces in the regex search code) and replace it with this.
${start}${type}? ${name}${body}${name} != null${ending}
You will have to manually change the backing field to nullable. I couldn’t come up with an easy way to change that through find replace.
If any of the properties are serialized as attributes this won’t work because you aren’t allowed to use nullable types there. Luckly I only had 3 of those cases and they were all enums.
[System.Xml.Serialization.XmlAttributeAttribute()]
public GenderType gender {
get { return this.genderField;}
set { this.genderField = value;
this.genderFieldSpecified = (value != 0);
}
}
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool genderSpecified {
get { return this.genderFieldSpecified;}
}
I then modified the enum to give the first enum a value of 1
public enum GenderType
{
Male = 1,
Female,
}