"Jeff T." <Je***@discussi ons.microsoft.c om> wrote in message news:7F******** *************** ***********@mic rosoft.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
IXmlSerializabl e.
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 IXmlSerializabl e.
- - - Inheritance.cs
using System;
using System.IO;
using System.Xml;
using System.Xml.Sche ma;
using System.Xml.Seri alization;
public class GenericItem
{
// Default constructors are required to be deserializable.
public GenericItem( ) { }
}
public class MoreSpecific : GenericItem
{
public MoreSpecific( ) { }
}
[XmlRoot("Generi cItem")]
public class VerySpecific : MoreSpecific, IXmlSerializabl e
{
public VerySpecific( ) { }
private string _word = String.Empty;
public string Word { get { return _word; } set { _word = value; } }
// What follows is the IXmlSerializabl e implementation.
public XmlSchema GetSchema( ) { return null; }
public void WriteXml( XmlWriter writer)
{
// writer.WriteSta rtElement( "GenericIte m");
writer.WriteSta rtElement( "MoreSpecific") ;
writer.WriteSta rtElement( "VerySpecific") ;
writer.WriteAtt ributeString( "Word", _word);
writer.WriteFul lEndElement( );
writer.WriteFul lEndElement( );
// writer.WriteFul lEndElement( );
}
public void ReadXml( XmlReader reader)
{
// Highly simplified XmlReader takes advantage of the fact I have only one attribute.
while ( reader.Read( ) )
if ( reader.HasAttri butes )
_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.x ml", FileMode.Create New);
xs.Serialize( fs, vs);
fs.Flush( );
fs.Close( );
#else // DESERIALIZE
FileStream fs = new FileStream( "specific.x ml", FileMode.Open);
VerySpecific vs = (VerySpecific) xs.Deserialize( fs);
fs.Close( );
Console.WriteLi ne( "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 IXmlSerializabl e 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?
- - - specifiedTooMuc h.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 XmlRootAttribut e 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 WriteStartDocum ent( ) [and of
course, WriteEndDocumen t( )]. 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 IXmlSerializabl e,
and implementing these well-known serialization and deserialization methods
that operate on XmlWriters and XmlReaders, respectively.
Derek Harmon