[quoted text, click to view] "Shailendra Batham" <sgbatham@sbcglobal.net> wrote in message news:uVoYc.13561$2%2.60@newssvr29.news.prodigy.com...
> <?xml version='1.0' encoding='UTF-8'?>
> <State>
> <California>
> <City>
> <LosAngeles></LosAngeles>
> <SantaMonica></SantaMonica>
> <City>
> </California>
> <Illinois>
> <City>
> <Chicago></Chicago>
> <City>
> </Illinois>
> </State>
>
> suppose this is my xml document, how can I achieve serialization and
> deserialization on this xml and get the results.
It's not possible to serialize/deserialize this based on serialization
attributes alone because you've encoded the "data" into the element
names, instead of using the elements to describe it's "structure." (I'm
not going to preach why this is generally a bad idea.)
Instead, it's necessary to implement the IXmlSerializable interface.
Here's what you'll need for this little project:
* One XML schema document (which in this case, cannot
be too well structured, but you need on nevertheless),
* Two methods, one deserializing from an XmlReader and the
other serializing into an XmlWriter.
Making this more concrete involves crafting up the essential object
model you've presupposed in your desired XML document, so let
me do that first. These classes will be light on luxury (the IEnumerable
implementation isn't necessary for serialization, but to simplify the
test driver) while stressing relevance.
- - - States.cs
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
public class CityObj
{
string cityName;
public CityObj( string cityName)
{
this.cityName = cityName;
}
public string City
{
get
{
return this.cityName;
}
set
{
this.cityName = value;
}
}
}
public class StateObj : IEnumerable
{
string stateName;
ArrayList cityList;
public StateObj( string stateName)
{
this.stateName = stateName;
this.cityList = new ArrayList( );
}
public StateObj( string stateName, CityObj[ ] cities)
{
this.stateName = stateName;
this.cityList = new ArrayList( cities);
}
public CityObj Add( string cityName)
{
CityObj city = new CityObj( cityName);
this.cityList.Add( city);
return city;
}
public string StateName
{
get
{
return this.stateName;
}
set
{
this.stateName = value;
}
}
IEnumerator IEnumerable.GetEnumerator( )
{
return ((IEnumerable)( this.cityList)).GetEnumerator( );
}
}
public class StateCollection : IXmlSerializable, IEnumerable
{
ArrayList stateList;
bool deserializedOK;
public StateCollection( )
{
this.stateList = new ArrayList( );
this.deserializedOK = true;
}
public bool IsOK
{
get
{
return this.deserializedOK;
}
}
public int Count
{
get
{
return this.stateList.Count;
}
}
public StateObj Add( string stateName)
{
StateObj st = new StateObj( stateName);
this.stateList.Add( st);
return st;
}
public StateObj Add( StateObj state)
{
this.stateList.Add( state);
return state;
}
IEnumerator IEnumerable.GetEnumerator( )
{
return ((IEnumerable)( this.stateList)).GetEnumerator( );
}
public XmlSchema GetSchema( )
{
// TO BE SUPPLIED.
}
public void ReadXml( XmlReader reader)
{
// TO BE SUPPLIED.
}
public void WriteXml( XmlWriter writer)
{
// TO BE SUPPLIED.
}
}
- - -
The first method of IXmlSerializable that you're going to implement
is GetSchema( ). This method needs to return an XML Schema
Document describing the expected format of the serialized instance
XML. Since I can't anticipate all of the states / provinces that your
application might require, there's very little I can do as far as defining
<xs:element>'s of it's structure. Instead, the heart of the lax schema
I'm going to use is the <xs:any> (note that the processContent attribute
is not allowed, however the any element will permit you free-wheeling
lattitude in the content of that element).
Here's the schema document, complete for your perusal.
- - - state.xsd
<?xml version='1.0'?>
<xs:schema id="States" xmlns:xs='
http://www.w3.org/2001/XMLSchema'>
<!-- Global Type Definitions -->
<xs:complexType name="StatesType">
<xs:sequence>
<!-- Allow literally any content in the empty xmlns='' -->
<xs:any namespace="##local" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<!-- Global Element Declaration -->
<xs:element name="States" type="StatesType" />
</xs:schema>
- - -
Now let's fill out the GetSchema( ) method, which simply loads
this file and returns a SOM XmlSchema instance.
public XmlSchema GetSchema()
{
FileStream xsdFile = new FileStream( "State.xsd", FileMode.Open);
// Optional ValidationEventHandler can be passed as 2nd argument here.
XmlSchema xsd = XmlSchema.Read( xsdFile, null);
xsdFile.Close( );
return xsd;
}
Pretty self-explanatory. Normally if we had had a more stringent
schema document, the step in which XmlSerializer gets the schema
would also perform schema-validation and it could detect validation
errors here (or notify your program through a ValidationEventHandler
you register in the XmlSchema.Read( ) method above).
The example I'm demonstrating will put the serialized content into a
container element named after the class, StateCollection, but
within there the content closely corresponds to what you want.
You may re-align the object model as is necessary for the app
at hand, but make sure you retain the xsd and xsi namespace
declarations.
Writing the XML out is the simplest operation, taking advantage
of the IEnumerable support in the object model we're using. It's
a straightforward application of the XmlWriter class that the
XmlSerializer will pass to this method when time comes to serialize
the StateCollection instance (or other IXmlSerializable implementation).
public void WriteXml( XmlWriter writer)
{
writer.WriteStartElement( "State");
writer.WriteAttributeString( "xmlns", "xsd", null, "
http://www.w3.org/2001/XMLSchema");
writer.WriteAttributeString( "xmlns", "xsi", null, "
http://www.w3.org/2001/XMLSchema-instance");