Writing and Reading XML





Writing and Reading XML

Underneath the covers, XML Serialization is using the stream-based parsers in System.Xml. As you've probably noticed in the samples thus far, you use streams to both read and write the XML. You can give it any stream object that is derived from the Stream base class. So, for example, you use a NetworkStream, or a FileStream.

The XmlSerializer object has two methods just for this purpose: Deserialize and Serialize. But before you can call these, you need to create an XmlSerializer for the specific type you are going to use.

XmlSerializer ser = new XmlSerializer( typeof(Customer) ); 

Creating a Type object is fairly straightforward, as you can see. One thing to keep in mind is that you will possibly need to create several of these, one for each class of object you are going to use.

Before you ever deserialize, make certain that the XML you are about to deserialize will map to the class with which you instantiated this serializer. You can easily do this with the CanDeserialize method.

if( ser.CanDeserialize( inStream ) ) 
{
     CustomerType cust = (CustomerType)ser2.Deserialize( inStream );
}

You've probably noticed that the XML that the XML Serializer produces contains the "<?xml" declaration. If, as often happens, you want to use the XML Serializer to write out a piece of XML into a currently existing XML document, then you won't want this "<?xml" declaration. If you hand the serializer an XmlWriter for an XML document that was already started, then this declaration will not appear.

The snippet that follows illustrates how you can use an XmlTextWriter with the XmlSerializer:

XmlSerializer ser = new XmlSerializer( typeof(Customer) ); 
FileStream stream = new FileStream("cust.xml",
                       FileMode.OpenOrCreate);
XmlTextWriter writer = new XmlTextWriter(
                       stream, new System.Text.UTF8Encoding() );
writer.WriteStartElement("Doc", "http://doc");
ser.Serialize( writer, t );
writer.WriteEndElement();
writer.Close();

Serializing Encoded XML

The SOAP specification pre-dates the XML Schema standard. As a result, Section 5 of the SOAP specification describes how to map common data types into XML without using schemas. XML that is based on Section 5 of the SOAP specification is commonly called encoded XML.

Although encoded XML was clearly designed for use within SOAP messages, at times you may want to use this kind of XML outside of SOAP. Also, you may want to create encoded XML for SOAP messages outside of the usual .NET Framework SOAP infrastructure. In those cases, you can create an XmlSerializer object that will serialize the objects you hand it as encoded XML.

To do this, you'll need to hand the XmlSerializer an XmlTypeMapping object in its constructor, instead of a Type object. Using the ImportTypeMapping method of the SoapReflectionImporter class can create this XmlTypeMapping object, as shown in the following snippet:

XmlTypeMapping typeMap = ( new SoapReflectionImporter()).ImportTypeMapping ( typeof(Customer) ); 
XmlSerializer encSer = new XmlSerializer( typeMap );
FileStream outStream = new FileStream(
          "enc.xml", FileMode.OpenOrCreate );
encSer.Serialize( outStream, t );
outStream.Close();

This serializer creates XML that looks very different from how the XML would look if it were literal XML:

<?xml version="1.0"?> 
<Customer
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     id="id1">
  <Name xsi:type="xsd:string">Keith Ballinger</Name>
  <Address xsi:type="xsd:string">1 Microsoft Way</Address>
  <PhoneNumber xsi:type="xsd:string">(425)555-1212</PhoneNumber>
</Customer>

As you may remember, you can control the serialization of XML with attributes. However, the attributes you use to control serialization when doing literal XML won't have any effect when serializing encoded XML. You may want to use the class with both literal XML and encoded XML, and you also may want to control the serialization of both, as both sets of classes come in handy.

Several attributes that start with the word Soap are used for controlling encoded XML Serialization. For example, to control the name of the element into which a member will serialize, you can use the [SoapElement] attribute. To control the namespace and root name of the class, you can use the [SoapType] attribute.

NOTE

The Soap attributes don't have exactly the best name. A better name prefix would have been "EncodedXml"—but since it would be very, very rare to use these attributes outside of SOAP, this is the prefix.

The following class uses the [SoapElement] attribute:

public class Customer 
{
     [SoapElement("CustomerName")]
     public String Name;
     public String Address;
     public String PhoneNumber;
}

And the resulting XML looks like this:

<?xml version="1.0"?> 
<Customer
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     id="id1">
       <CustomerName
            xsi:type="xsd:string">Keith Ballinger</CustomerName>
  <Address
       xsi:type="xsd:string">1 Microsoft Way</Address>
  <PhoneNumber
       xsi:type="xsd:string">(425)555-1212</PhoneNumber>
</Customer>

     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows