"Jeff T." <Je***@discussions.microsoft.com> wrote in message news:7F**********************************@microsof t.com...
I would like to serialize these data objects as XML but perserve the
[inheritance] relationships in the XML document.
: : Does anyone know which XML Attributes I should apply to my class properties
so these relationships are maintained? Is this even the best approach?
If you require this degree of customization over the serialized
representation of your objects, then you'll need to implement
IXmlSerializable.
Here is an example. I add a piece of data, the 'Word' property,
to the VerySpecific subclass so there's something tangible to
serialize. I also arbitrarily chose to serialize that property as an
attribute. As you'll see, the representation is highly flexible when
using IXmlSerializable.
- - - Inheritance.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
public class GenericItem
{
// Default constructors are required to be deserializable.
public GenericItem( ) { }
}
public class MoreSpecific : GenericItem
{
public MoreSpecific( ) { }
}
[XmlRoot("GenericItem")]
public class VerySpecific : MoreSpecific, IXmlSerializable
{
public VerySpecific( ) { }
private string _word = String.Empty;
public string Word { get { return _word; } set { _word = value; } }
// What follows is the IXmlSerializable implementation.
public XmlSchema GetSchema( ) { return null; }
public void WriteXml( XmlWriter writer)
{
// writer.WriteStartElement( "GenericItem");
writer.WriteStartElement( "MoreSpecific");
writer.WriteStartElement( "VerySpecific");
writer.WriteAttributeString( "Word", _word);
writer.WriteFullEndElement( );
writer.WriteFullEndElement( );
// writer.WriteFullEndElement( );
}
public void ReadXml( XmlReader reader)
{
// Highly simplified XmlReader takes advantage of the fact I have only one attribute.
while ( reader.Read( ) )
if ( reader.HasAttributes )
_word = reader[0];
}
}
public class TestApp
{
public static void Main( )
{
XmlSerializer xs = new XmlSerializer( typeof( VerySpecific));
#if SERIALIZE
VerySpecific vs = new VerySpecific( );
vs.Word = "Is Born";
FileStream fs = new FileStream( "specific.xml", FileMode.CreateNew);
xs.Serialize( fs, vs);
fs.Flush( );
fs.Close( );
#else // DESERIALIZE
FileStream fs = new FileStream( "specific.xml", FileMode.Open);
VerySpecific vs = (VerySpecific) xs.Deserialize( fs);
fs.Close( );
Console.WriteLine( "Word {0}", vs.Word);
#endif
}
}
- - -
When you define 'SERIALIZE' in your C# project settings (or via the csc
command-line with the -D option) and build this test application, it'll produce
a serialization of a VerifySpecific object like the following:
- - - specific.xml
<?xml version="1.0" encoding="utf-8"?>
<GenericItem>
<MoreSpecific>
<VerySpecific Word="Is Born"></VerySpecific>
</MoreSpecific>
</GenericItem>
- - -
It does this in two steps. First, the XmlSerializer will put all of the XML produced
by your IXmlSerializable implementation's WriteXml( ) into an element named after
the class being serialized. We have a problem -- the class being serialized is named
VerySpecific. How do we avoid generating?
- - - specifiedTooMuch.xml
<?xml version="1.0" encoding="utf-8"?>
<VerySpecific>
<GenericItem>
<MoreSpecific>
<VerySpecific Word="Is Born"></VerySpecific>
</MoreSpecific>
</GenericItem>
</VerySpecific>
- - -
We can trick the XmlSerializer into putting the XML content into an outer element
named GenericItem if we use an XmlRootAttribute on the VerySpecific class.
Having done so, it's no longer necessary for our WriteXml( ) implementation to
write out GenericItem elements, so that's why those have been commented out.
Also note that the XmlWriter you receive in WriteXml( ) is already writing an
XML serialization; so it's not necessary to call WriteStartDocument( ) [and of
course, WriteEndDocument( )]. In fact, you'll get an error if you try to.
That covers serialization; now on to deserialization. The XmlReader use shown
in ReadXml( ) is very simple since there's only one property here; you may need
to craft your XmlReader code with greater care depending on the characteristics
of your desired serialization format.
Build the Inheritance.cs file without defining SERIALIZATION and it'll operate
in de-serialization mode, reading the specific.xml file it has just written and printing
the very hip message,
Word Is Born
It does this by handing an XmlReader to your implementation of ReadXml( ).
This method is responsible for retrieving any information in the XML serialization
format and mapping that information into your object's properties.
For serialization and deserialization with XmlSerializer, there is no need to
supply an XmlSchema. The XmlSerializer doesn't perform schema-validation
on the XML when it's deserializing it.
In summary, when you need total control over the representation of the
XML when serializing/deserializing, you can fallback to IXmlSerializable,
and implementing these well-known serialization and deserialization methods
that operate on XmlWriters and XmlReaders, respectively.
Derek Harmon