Sunday 25 March 2007

XmlSerializer and minOccurs="0" collections: that pesky xxxSpecified magic

I'm attempting to decorate the properties in a class so when it's serialised by the XmlSerializer, it adheres to a schema that looks, in part, like this:

<xs:element minoccurs="0" name="Locations">
<?xml:namespace prefix = xs /><xs:complextype>
<xs:sequence>
<xs:element name="Location" maxoccurs="unbounded" type="xs:string">
</xs:sequence>
</xs:complextype>

Basically, I've got a class that contains a Locations collections; if the collection has one or more items, it should be serialized and if it has zero items, it shouldn't be serialized and, most importantly, the Locations element should NOT appear in the serialized document.

Running the property below through the XmlSerializer works fine if the collection is populated but results in an empty element if the collection is empty.

So this:

[System.Xml.Serialization.XmlArrayItemAttribute ("Location")]
public List Locations
{
get
{
return SearchAttributes.Locations;
}
}

populated at runtime with zero items results in this:

<locations>

And schema validation fails.

I've looked at various attributes trying to find something that will optionally serialize an element or collection but nothing jumps out.

XSD.exe produces the following property from the schema but by itself does nothing to help out here.

[System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
[System.Xml.Serialization.XmlArrayItemAttribute("Location", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
public string[] Locations {
get {
return this.locationsField;
}
set {
this.locationsField = value;
}
}

Another XSD example produced an xxxSpecified property for a minOccurs="0" element (not a collection) and setting it false does remove the element from the output; I can't figure out why this works though! Sticking it into my own class does some sort of magic though:


private bool locationsSpecified;

[System.Xml.Serialization.XmlIgnoreAttribute ()]
public bool LocationsSpecified
{
get
{
return this.locationsSpecified;
}
set
{
this.locationsSpecified = value;
}
}


The LocationsSpecified property is simply set by the caller and voila, Locations disappears if empty.

No comments:

Post a Comment

Spam comments will be deleted

Note: only a member of this blog may post a comment.