471,594 Members | 1,701 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,594 software developers and data experts.

XML Serialization Help

Hello,
I have an existing set of C# classes that encapsulate our application data.
They are in a heirachy with each subclass defining more specific types of
data. I would like to serialize these data objects as XML but perserve the
relationships in the XML document. For example, if my classes were:

public class GenericItem
{
}

public class MoreSpecific : GenericItem
{
}

public class VerySpecific : MoreSpecific
{
}

I would like the XML document to look like,
<GenericItem>
<MoreSpecific>
<VerySpecific></VerySpecific>
</MoreSpecific>
</GenericItem>

Does anyone know which XML Attributes I should apply to my class properties
so these relationships are maintained? Is this even the best approach? Any
advice or suggestions are greatly appreciated.

Thanks,
Jeff
Nov 12 '05 #1
4 3003
"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
Nov 12 '05 #2
Derek,
Thanks for the very helpful reply. A few follow-up questions.....

- Since the IXmlSerializable interface is not even documented by
Microsoft, I wonder if this is the best approach. Perhaps I should
rewrite my data classes so they can be automatically serialized? Will
the tradeoffs of doing this be better in the long run?

- If I were to rewrite my data classes, I assume I would need to use a
containership model instead of an inheritance model. In other words,
the classes would have a "HAS A" instead of an "IS A" relationship. The
XML Serialization model does not apply well to Object Oriented
Programming, does it?

- You mentioned that a schema would not need to be supplied. What if I
was to supply a schema? I want the receivers of my data to know how to
read it, as there is no guarantee that my same data classes will be
used on the receiving end. Can a schema be generated automatically or
do I have to define one manually?

Thanks again,
Jeff

Nov 12 '05 #3
"Jeff T." <yo****@comcast.net> wrote in message news:11**********************@g14g2000cwa.googlegr oups.com...
- Since the IXmlSerializable interface is not even documented by
Microsoft, I wonder if this is the best approach. Perhaps I should
rewrite my data classes so they can be automatically serialized? Will
the tradeoffs of doing this be better in the long run?
IXmlSerializable was somewhat more documented in .NET 2.0;
so it's still there, for what that's worth. Generally you're right that its
best to avoid types that are undocumented. In this particular case,
it is being used to solve the problem of (de)serializing of XML using
XmlSerializer in whatever format an application requires so in a de
facto way there would probably be reticence to take IXmlSerializable
away in future releases. That's not to say the interface might not be
changed if the process of XML (de)serialization needed some new
step that the interface doesn't presently define, albeit unlikely.

Let's look at implementing a (de)serialization API yourself. What
methods would it have? A WriteXml method, that writes to the abstract
XmlWriter class? A ReadXml method, that reads from an abstract
XmlReader class? Well, if that's what you're going to implement anyway,
ironically it already exists on IXmlSerializable. :-)

The only difference is without marking the class as implementing the
IXmlSerializable interface, you must call these methods yourself. If
you implement IXmlSerializable, the XmlSerializer will call them for
you.
- If I were to rewrite my data classes, I assume I would need to use a
containership model instead of an inheritance model. In other words,
the classes would have a "HAS A" instead of an "IS A" relationship. The
XML Serialization model does not apply well to Object Oriented
Programming, does it?
XML is all about containment, so it's natural a serialization in XML
has a less than optimal representation for inheritance compared to
a containment model (or that inheritance must be represented by
containment).

I have seen the XML schema you've shown used to represent
inheritance in the past, though. It's not disimilar to the approach
of binary serialization.
- You mentioned that a schema would not need to be supplied.
What if I was to supply a schema?
XmlSerializer won't use it for anything.

The .NET 2.0 Beta 1 documentation states that the XmlSchema is
needed only for generating WSDL proxies, and that it's not called
for serialization/deserialization of instances because XmlSerializer
doesn't schema-validate (which is just as well, because it'd incur
considerable overhead to do so).
I want the receivers of my data to know how to
read it,
You can send them an XML schema document out-of-band, for
example you can implement WriteXml( ) to serialize an xsi:schema-
Location attribute. It's up to the consumer to retrieve it if they need
it.

How much it truly helps the consumers know how to read your
XML instance depends on whether the consuming application is
intelligent enough to use it to generate and execute dynamic code.
Most XML consumers aren't built that well, though, or at least
few of us are fortunate enough to have them be commonplace.
as there is no guarantee that my same data classes will be
used on the receiving end. Can a schema be generated
automatically or do I have to define one manually?


There's an XML Schema Inference tool here,

http://apps.gotdotnet.com/xmltools/xsdinference/

Several popular XML editors also include it as a
feature. The better implementations allow you to
specify heuristics to improve the inference.

At least, you can pass xsd.exe a file with an .xml
extension and it'll infer a schema document.

After one of these programs guesses one of the millions of
possible schemas that will validate your instance document,
it's wise to revise it manually. :-)
Derek Harmon
Nov 12 '05 #4
Once again you have been very helpful. Thank you.

Jeff

Nov 12 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Aaron Clamage | last post: by
2 posts views Thread by Dave Veeneman | last post: by
5 posts views Thread by francois | last post: by
6 posts views Thread by Uttam | last post: by
4 posts views Thread by mdb | last post: by
4 posts views Thread by Brian Keating | last post: by
8 posts views Thread by =?Utf-8?B?UGlnZ3k=?= | last post: by
reply views Thread by leo001 | last post: by
reply views Thread by Anwar ali | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.