XML Serialization

The simplest way to demonstrate Visual Basic's support for XML is to use it to serialize a class. The serialization of an object means that it is written out to a stream, such as a file or a socket. The reverse process can also be performed: an object can be deserialized by reading it from a stream and creating the XML from that stream. You may want to do this to save an object's data to a local file, or to transmit it across a network.


Note
The type of serialization described in this chapter is XML serialization, whereby XML is used to represent a class in serialized form. You will see other forms of serialization in the WCF chapter (Chapter 11).

To help you understand XML serialization, let's examine a class named FilmOrder in the FilmOrder project. This class could be used by a company for processing a movie order.

An instance of FilmOrder corresponding to each order could be serialized to XML and sent over a socket from a client's computer. We are talking about data in a proprietary form here: an instance of FilmOrder being converted into a generic form—XML—that can be universally understood.

The System.Xml.Serialization namespace contains classes and interfaces that support the serialization of objects to XML, and the deserialization of objects from XML. Objects are serialized to documents or streams using the XmlSerializer class.

Serializing

Let's look at how you can use XmlSerializer. To make the sample simpler, you'll use a console application. This console application will use the class FilmOrder as follows (code file: Main.vb):

Public Class FilmOrder
  Public Name As String
  Public FilmId As Integer
  Public Quantity As Integer
  Public Sub New()
  End Sub
  Public Sub New(ByVal name As String, _
                 ByVal filmId As Integer, _
                 ByVal quantity As Integer)
    Me.Name = name
    Me.FilmId = filmId
    Me.Quantity = quantity
  End Sub
End Class

From there, you can move on to the module.

To make the XmlSerializer object accessible, you need to make reference to the System.Xml.Serialization namespace:

Imports System.Xml.Serialization

In the Sub Main, create an instance of XmlSerializer, specifying the type to be serialized, this case, the FilmOrder type:

Dim serialize As XmlSerializer = _
  New XmlSerializer(GetType(FilmOrder))

Next, you create an instance of the FilmOrder class, or whatever class it was that you provided the type for in the previous step. In a more complex application, you may have created this instance using data provided by the client, a database, or other source:

Dim MyFilmOrder As FilmOrder = _
  New FilmOrder("Grease", 101, 10)

Note
It is important for you to know that serialization, and deserialization, use reflection. For that reason, the class being serialized must include a parameterless constructor. If it does not, attempting to serialize it will result in an exception.

Call the Serialize method of the XmlSerializer instance specifying Console.Out as the output stream and the object to be serialized.

serialize.Serialize(Console.Out, MyFilmOrder)
Console.ReadLine()

Running the module, the following output is generated by the preceding code:

<?xml version="1.0" encoding="IBM437"?>
<FilmOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Grease</Name>
  <FilmId>101</FilmId>
  <Quantity>10</Quantity>
</FilmOrder>

This output demonstrates the default way in which the Serialize method serializes an object:

  • Each object serialized is represented as an element with the same name as the class—in this case, FilmOrder.
  • The individual data members of the class serialized are contained in elements named for each public data member—in this case, Name, FilmId, and Quantity.

Also generated are the following:

  • The specific version of XML generated—in this case, 1.0
  • The encoding used for the text—in this case, IBM437
  • The schemas used to describe the serialized object—in this case, just the two schemas defined by the XML schema specification, www.w3.org/2001/XMLSchema-instance and www.w3.org/2001/XMLSchema

A schema can be associated with an XML document and describes the data it contains (name, type, scale, precision, length, and so on). Either the actual schema or a reference to where the schema is located can be contained in the XML document. In either case, an XML schema is a standard representation that can be used by all applications that consume XML. This means that applications can use the supplied schema to validate the contents of an XML document generated by the Serialize method of the XmlSerializer object.

The code snippet that demonstrated the Serialize method displayed the generated XML to the Console.Out stream. Clearly, you do not expect an application to use Console.Out when it would like to access a FilmOrder object in XML form. The point was to show how serialization can be performed in just two lines of code, one call to a constructor and one call to a method.

The Serialize method's first parameter is overridden so that it can serialize XML to a file, a Stream, a TextWriter, or an XmlWriter. When serializing to Stream, TextWriter, or XmlWriter, adding a third parameter to the Serialize method is permissible. This third parameter is of type XmlSerializerNamespaces and is used to specify a list of namespaces that qualify the names in the XML-generated document.

Deserializing

Since serialization produces an XML document from an object, it stands to reason that deserialization would do the opposite. This is handled by the Deserialize method of XmlSerializer. This method is overridden and can deserialize XML presented as a Stream, a TextReader, or an XmlReader. The output of the various Deserialize methods is a generic Object, so you need to cast the resulting object to the correct data type.

The example that demonstrates how to deserialize an object can be found in the FilmOrderList project. This is just an updated version of the previous example. The first step is to look at the new FilmOrderList class. This class contains an array of film orders (actually an array of FilmOrder objects). FilmOrderList is defined as follows (code file: FileMorderList.vb):

Public Class FilmOrderList
    Public FilmOrders() As FilmOrder
    Public Sub New()
    End Sub
    Public Sub New(ByVal multiFilmOrders() As FilmOrder)
        Me.FilmOrders = multiFilmOrders
    End Sub
End Class

The FilmOrderList class contains a fairly complicated object, an array of FilmOrder objects. The underlying serialization and deserialization of this class is more complicated than that of a single instance of a class that contains several simple types, but the programming effort involved on your part is just as simple as before. This is one of the great ways in which the .NET Framework makes it easy for you to work with XML data, no matter how it is formed.

To work through an example of the deserialization process, first create a sample order stored as an XML file called Filmorama.xml:

<?xml version="1.0" encoding="utf-8" ?>
<FilmOrderList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <FilmOrders>
    <FilmOrder>
      <Name>Grease</Name>
      <FilmId>101</FilmId>
      <Quantity>10</Quantity>
    </FilmOrder>
    <FilmOrder>
      <Name>Lawrence of Arabia</Name>
      <FilmId>102</FilmId>
      <Quantity>10</Quantity>
    </FilmOrder>
    <FilmOrder>
      <Name>Star Wars</Name>
      <FilmId>103</FilmId>
      <Quantity>10</Quantity>
    </FilmOrder>
  </FilmOrders>
</FilmOrderList>

Note
In order for this to run, you should either have the .xml file in the location of the executable or load the file using the full path of the file within the code example. To have the XML in the same directory as the executable, add the XML file to the project, and set the Copy to Output Directory to “Copy if newer.”

Once the XML file is in place, the next step is to change your console application so it will deserialize the contents of this file. First, ensure that your console application has made the proper namespace references:

Imports System.Xml
Imports System.Xml.Serialization
Imports System.IO

The code that actually performs the deserialization is found in the Sub Main()method (code file: Main.vb):

’ Open file Filmorama.xml
Dim dehydrated As FileStream = _
   New FileStream("Filmorama.xml", FileMode.Open)
’ Create an XmlSerializer instance to handle deserializing,
’ FilmOrderList
Dim serialize As XmlSerializer = _
   New XmlSerializer(GetType(FilmOrderList))
’ Create an object to contain the deserialized instance of the object.
Dim myFilmOrder As FilmOrderList = _
   New FilmOrderList
’ Deserialize object
myFilmOrder = serialize.Deserialize(dehydrated)

This code demonstrates the deserialization of the Filmorama.xml file into a FilmOrderList instance. This is accomplished, mainly, by the call to the Deserialize method of the XmlSerializer class.

Once deserialized, the array of film orders can be displayed. The following code shows how this is accomplished (code file: Main.vb):

Dim SingleFilmOrder As FilmOrder
For Each SingleFilmOrder In myFilmOrder.FilmOrders
   Console.Out.WriteLine("{0}, {1}, {2}", _
      SingleFilmOrder.Name, _
      SingleFilmOrder.FilmId, _
      SingleFilmOrder.Quantity)
Next
Console.ReadLine()

Running the example will result in the following output:

Grease, 101, 10
Lawrence of Arabia, 102, 10
Star Wars, 103, 10

XmlSerializer also implements a CanDeserialize method. The prototype for this method is as follows:

Public Overridable Function CanDeserialize(ByVal xmlReader As XmlReader) _
   As Boolean

If CanDeserialize returns True, then the XML document specified by the xmlReader parameter can be deserialized. If the return value of this method is False, then the specified XML document cannot be deserialized. Using this method is usually preferable to attempting to deserialize and trapping any exceptions that may occur.

The FromTypes method of XmlSerializer facilitates the creation of arrays that contain XmlSerializer objects. This array of XmlSerializer objects can be used in turn to process arrays of the type to be serialized. The prototype for FromTypes is shown here:

Public Shared Function FromTypes(ByVal types() As Type) As XmlSerializer()

Source Code Style Attributes

Thus far, you have seen attributes applied to a specific portion of an XML document. Visual Basic, as with most other languages, has its own flavor of attributes. These attributes refer to annotations to the source code that specify information, or metadata, that can be used by other applications without the need for the original source code. You will call such attributes Source Code Style attributes.

In the context of the System.Xml.Serialization namespace, Source Code Style attributes can be used to change the names of the elements generated for the data members of a class or to generate XML attributes instead of XML elements for the data members of a class. To demonstrate this, you will update the FilmOrder class using these attributes to change the outputted XML. This updated version is part of the new example found in the FilmOrderAttributes project.

In the previous section, you saw that serialization used the name of the property as the name of the element that is automatically generated. To rename this generated element, a Source Code Style attribute will be used. This Source Code Style attribute specifies that when FilmOrder is serialized, the name data member is represented as an XML element named <Title>. The actual Source Code Style attribute that specifies this is as follows:

<XmlElementAttribute("Title")> 
Public Name As String

The updated FilmOrder also contains other Source Code Style attributes (code file: FilmOrder.vb):

Imports System.Xml.Serialization
Public Class FilmOrder
  <XmlElementAttribute("Title")> Public Name As String
  <XmlAttributeAttribute("ID")> Public FilmId As Integer
  <XmlAttributeAttribute("Qty")> Public Quantity As Integer
  Public Sub New()
  End Sub
  Public Sub New(ByVal name As String, _
                 ByVal filmId As Integer, _
                 ByVal quantity As Integer)
      Me.Name = name
      Me.FilmId = filmId
      Me.Quantity = quantity
  End Sub
End Class

The additional attributes that were added to the example class are:

  • <XmlAttributeAttribute(”ID”)> specifies that FilmId is to be serialized as an XML attribute named ID.
  • <XmlAttributeAttribute(”Qty”)> specifies that Quantity is to be serialized as an XML attribute named Qty.

Note that you needed to include the System.Xml.Serialization namespace to bring in the Source Code Style attributes used.

The following Sub Main() method for this project is no different from the ones previously shown (code file: Main.vb):

Dim serialize As XmlSerializer = _
    New XmlSerializer(GetType(FilmOrder))
Dim MyMovieOrder As FilmOrder = _
    New FilmOrder("Grease", 101, 10)
serialize.Serialize(Console.Out, MyMovieOrder)
Console.Readline()

The console output generated by this code reflects the Source Code Style attributes associated with the class:

<?xml version="1.0" encoding="IBM437"?>
<FilmOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="101" Qty="10">
  <Title>Grease</Title>
</FilmOrder>

Compare this to the earlier version that does not include the attributes.

The example only demonstrates the Source Code Style attributes XmlAttributeAttribute and XmlElementAttribute. Table 8.1 shows some additional attributes available.

Table 8.1 Additional Source Code Attributes Available

Attribute Description
XmlArrayAttribute Allows the name of an array element to be specified.
XmlArrayItemAttribute Allows the name of an array's child elements to be specified.
XmlRoot Denotes the root element.
XmlType Used to specify the data type for an element. This is used in XSD files, which are discussed later.
XmlIgnoreAttribute Instructs the serializer to not serialize the current element or attribute.
XmlEnumAttribute Controls how enumeration values are serialized.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset