Chapter 15: XML and .NET


Microsoft has been working for years to make using XML in the .NET world as easy as possible. You can't help but notice the additional capability and the enhancements to overall XML usage introduced in new each version of the .NET Framework. In fact, Bill Gates highlighted Microsoft's faith in XML in his keynote address at the Microsoft Professional Developers Conference 2005 in Los Angeles. He stated that XML is being pushed deeper and deeper into the Windows core each year. If you look around the .NET Framework, you will probably agree.

In addition to a series of namespaces in the .NET Framework that deal with XML and other XML-related technologies, you also find support for XML in Microsoft's products such as Visual Studio 2005, ASP.NET, ADO.NET, SQL Server, BizTalk, and a plethora of others.

This and the following two chapters step away from focusing on a specific XML technology. Instead, they focus on how specific vendors' technologies use XML. This chapter takes a look at XML in the .NET world, while the next few chapters look at XML in the worlds of Java, PHP, and more. You start by looking specifically at the Microsoft's embrace of XML.

The Serialization of XML

The .NET Framework makes it rather simple to serialize an object, such as a class, to XML. This has a lot of value in that you can take any objects you create in the .NET world, serialize them to XML, and then transport this XML over the wire or save it to disk for later retrieval. The serialization of an object means that it is written out to a stream, such as a file or a socket (this is also known as dehydrating an object). The reverse process can also be performed: An object can be deserialized (or rehydrated) by reading it from a stream.

For this entire process, the .NET Framework provides you with the System.Xml.Serialization namespace. This namespace contains all the classes and interfaces you need to support the serialization and deserialization of objects to and from XML.

Serializing Using the XmlSerializer Class

For an example of the serialization capabilities supported by the .NET Framework, you can create a C# console application. In this console application, you first create a class to be serialized to XML using the XmlSerializer class found in the System.Xml.Serialization namespace. Listing 15-1 provides you with the class you will use first. Place this class inside the project of the console application.

Listing 15-1: A simple class that will later be used in the serialization process

image from book
      using System;      using System.Collections.Generic;      using System.Text;      namespace XmlSerializationProject      {          public class StockOrder          {              private string _symbol;              private int _quantity;              private DateTime _OrderTime = DateTime.Now;              public string Symbol              {                  get { return _symbol; }                  set { _symbol = value; }              }              public int Quantity              {                  get { return _quantity; }                  set { _quantity = value; }              }              public DateTime OrderTime              {                  get { return _OrderTime; }                  set { _OrderTime = value; }              }          }      } 
image from book

After the StockOrder class is in place in your console application project, the next step is to populate some of the properties this class exposes and use the XmlSerializer to convert the object to XML. The code for the console application is shown in Listing 15-2.

Listing 15-2: Serializing the StockOrder class to XML

image from book
      using System;      using System.Collections.Generic;      using System.Text;      using System.Xml.Serialization;      namespace XmlSerializationProject       {          class Program          {              static void Main(string[] args)              {                  try                  {                     XmlSerializer classSerialization =                         new XmlSerializer(typeof(StockOrder));                     StockOrder so = new StockOrder();                     so.Symbol = "MSFT";                     so.Quantity = 100;                     classSerialization.Serialize(Console.Out, so);                     Console.ReadLine();                  }                  catch (System.Exception ex)                  {                     Console.Error.WriteLine(ex.ToString());                     Console.ReadLine();                  }              }          }      } 
image from book

In the previous listing, the Serialize method of the XmlSerializer instance is what you use to serialize the object to a specified stream. In the case of Listing 15-2, the Serialize instance is using two parameters-the first specifying the stream (in this case, Console.Out) and the second specifying the object to be serialized (in this case, so). The output generated from this simple application is illustrated in Figure 15-1.

image from book
Figure 15-1

The output shows that each public property is represented as an XML element which has the same name as the exposed property from the StockOrder class. Along that vein, the root element of the XML document has the same name as the class-StockOrder.

As with a typical XML document, the output includes a version specification of the XML as well as the encoding attribute with the value of IBM437. This encoding value is used because the console application really ends up using the TextWriter object to output the XML. Using some other type of object, the XmlTextWriter object, for instance, enables you more direct control over the encoding type used in the XML creation.

Besides the encoding attribute, a couple of namespaces are added to the XML document on your behalf:

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 

The end result shows that the simple object that was created has been output with a single set of results to the console application through the use of the XmlSerializer object. Next, you examine how you go about changing some of the output that is generated for you by the .NET Framework.

Changing the Output of the Serialized Object

The XML serialization that was generated and displayed in Figure 15-1 may be acceptable for your object serialization, but then again, you might want to modify the output so that it is more to your liking. For instance, if you want to change the name used for the root node, you can easily accomplish this task through the use of XmlRootAttribute class as shown in Listing 15-3.

Listing 15-3: Using the XmlRootAttribute class to change the root element's name

image from book
      using System;      using System.Collections.Generic;      using System.Text;      using System.Xml.Serialization;      namespace XmlSerializationProject      {          class Program          {              static void Main(string[] args)              {                  try                  {                     XmlRootAttribute ra = new XmlRootAttribute();                     ra.ElementName = "ReutersStockOrder";                     XmlSerializer classSerialization =                         new XmlSerializer(typeof(StockOrder), ra);                     StockOrder so = new StockOrder();                     so.Symbol = "MSFT";                     so.Quantity = 100;                     classSerialization.Serialize(Console.Out, so);                     Console.ReadLine();                  }                  catch (System.Exception ex)                  {                     Console.Error.WriteLine(ex.ToString());                     Console.ReadLine();                  }              }          }      } 
image from book

Using the XmlRootAttribute class, you can programmatically alter how the XmlSerializer object serializes the respective class to XML. In this case, Listing 15-3 simply changes the name of the root element by first creating an instance of the XmlRootAttribute class and then using the ElementName property to make an assignment.

After you have instantiated the XmlRootAttribute class and set it up as desired, you assign the instance to the serialization process by adding it as a parameter in the instantiation of the XmlSerializer object.

      XmlSerializer classSerialization = new XmlSerializer(typeof(StockOrder), ra); 

Employing the code from Listing 15-3, you get the results illustrated in Figure 15-2.

image from book
Figure 15-2

In addition to changing the name used in the root element programmatically, you can also accomplish the same task declaratively directly in the StockOrder.cs file. This is illustrated in Listing 15-4.

Listing 15-4: Changing the name used in the root element declaratively

image from book
      using System;      using System.Collections.Generic;      using System.Text;      namespace XmlSerializationProject      {          [XmlRoot(ElementName = "ReutersStockOrder")]          public class StockOrder          {             // Code removed for clarity          }      } 
image from book

Using the XmlRoot attribute prior to the class declaration is another way to accomplish this task. Within the attribute declaration, you can use the ElementName named property to provide an overriding name for the root element-in this case, ReutersStockOrder. This could also have been accomplished using the following syntax:

      [XmlRoot("ReutersStockOrder")]      public class StockOrder      {          // Code removed for clarity      } 

In addition to the ElementName property, other properties include: DateType, IsNullable, and Namespace. Listing 15-5 shows an example of adding a new property, a namespace, to the generated output.

Listing 15-5: Adding a namespace to the serialized output

image from book
      using System;      using System.Collections.Generic;      using System.Text;      using System.Xml.Serialization;      namespace XmlSerializationProject      {          [XmlRoot(ElementName = "ReutersStockOrder",              Namespace = "http://www.reuters.com/namespaces/")]          public class StockOrder          {             // Code removed for clarity          }      } 
image from book

Listing 15-5 not only changes the name used in the root element, but it also adds another namespace to this root element. The results are shown in Figure 15-3.

image from book
Figure 15-3

You can also programmatically add namespaces and prefixes to the serialization process through the use of the XmlSerializerNamespaces class. This is illustrated in Listing 15-6:

Listing 15-6: Adding namespaces and prefixes to the serialization process

image from book
      using System;      using System.Collections.Generic;      using System.Text;      using System.Xml.Serialization;      namespace XmlSerializationProject      {          class Program          {              static void Main(string[] args)              {                  try                  {                     XmlSerializer classSerialization =                         new XmlSerializer(typeof(StockOrder));                     XmlSerializerNamespaces serName =                         new XmlSerializerNamespaces();                     serName.Add("reu", "http://www.reuters.com/ns/");                     serName.Add("lip", "http://www.lipperweb.com/ns/");                     StockOrder so = new StockOrder();                     so.Symbol = "MSFT";                     so.Quantity = 100;                     classSerialization.Serialize(Console.Out, so, serName);                     Console.ReadLine();                  }                  catch (System.Exception ex)                  {                     Console.Error.WriteLine(ex.ToString());                     Console.ReadLine();                  }              }          }      } 
image from book

The changes made to the console application include the addition of the XmlSerializerNamespaces class. In the application, an instance of this class is created (serName), and using the Add method allows you to define a prefix (reu or lip) as well as the namespace-both string values. The other and final change to the application is the parameter XmlSerializerNamespaces, which is added to the Serialize method of the XmlSerializer object instance (classSerialization).

After the prefixes and namespaces are in place in the application and ready to use, the next step is to change the StockOrder.cs file so that these namespaces are utilized by either the entire class or by particular properties declared in the class. This is illustrated in Listing 15-7.

Listing 15-7: Utilizing namespaces in the StockOrder.cs file

image from book
      using System;      using System.Collections.Generic;      using System.Text;      using System.Xml.Serialization;      namespace XmlSerializationProject      {          [XmlRoot(Namespace="http://www.lipperweb.com/ns/")]          public class StockOrder          {              private string _symbol;              private int _quantity;              private DateTime _OrderTime = DateTime.Now;              [XmlElement(Namespace="http://www.reuters.com/ns/")]              public string Symbol              {                   get { return _symbol; }                  set { _symbol = value; }              }              public int Quantity              {                  get { return _quantity; }                  set { _quantity = value; }              }              public DateTime OrderTime              {                  get { return _OrderTime; }                  set { _OrderTime = value; }              }          }      } 
image from book

From Listing 15-7, you can see that by simply using the XmlRoot and XmlElement attributes, the same programmatically declared namespaces can be used in the serialization process. The nice thing is that the prefixes will be properly placed in the appropriate elements contained in the XML document as well. This is illustrated in Figure 15-4.

image from book
Figure 15-4

The results show that through the use the XmlRoot attribute, the root element and all the elements but one (<Symbol>) are provided with the appropriate namespace prefixes. <Symbol> was written as <reu:Symbol> because the declarations done by the XmlRoot attribute are overridden through the use of the XmlElement attribute.

Not only can you declaratively alter the serialized output by adding an attribute before the class declaration in the StockOrder.cs file (as shown previously), but you can also perform a similar operation by adding an XmlElement attribute before any property declarations contained in the same class.

For instance, if you look at the <OrderTime> element in Figure 15-4, note that you are getting back a very detailed version (universal time) of DateTime.

      2005-10-04T11:09:32.1608608-5:00 

What if you wanted this to be a different type of date, one that is easily passed to other bits of code? Using the XmlElement attribute, you can assign data types to use for your properties. This is illustrated in Listing 15-8.

Listing 15-8: Assigning a specific data type to an element

image from book
            using System;      using System.Collections.Generic;      using System.Text;      using System.Xml.Serialization;      namespace XmlSerializationProject      {          public class StockOrder          {              private string _symbol;              private int _quantity;              private DateTime _OrderTime = DateTime.Now;              public string Symbol              {                  get { return _symbol; }                  set { _symbol = value; }              }              public int Quantity              {                  get { return _quantity; }                  set { _quantity = value; }              }              [XmlElement(DataType = "date")]              public DateTime OrderTime              {                  get { return _OrderTime; }                  set { _OrderTime = value; }              }          }      } 
image from book

Just as you used the XmlRoot attribute before the class declaration, you can easily add XmlElement attributes to any of your properties to further refine how the XML will be serialized. In this case, the DataType value is given a value of date, which is an XML-Schema-defined data type. The new output of serialized XML is shown in Figure 15-5.

image from book
Figure 15-5

In addition to the DataType property for the XmlElementAttribute class, you can also use the attributes detailed in the following table.

Open table as spreadsheet

Public Property

Description

DataType

Allows you to get or set the XML Schema defined data type of the XML element (for example, date).

ElementName

Allows you to get or set the name of the element that will be generated.

Form

Allows you to get or set a value that specifies whether the element is qualified.

IsNullable

Allows you to determine whether the XmlSerializer object should serialize elements where a null value is held. This property takes a Boolean value.

Namespace

Allows you to get or set a namespace for a particular XML element.

Order

Allows you to get or set the order in which elements are serialized or deserialized.

Type

Allows you to get or set the object type that is used to represent the XML element.

TypeId

Provides a unique identifier.




Professional XML
Professional XML (Programmer to Programmer)
ISBN: 0471777773
EAN: 2147483647
Year: 2004
Pages: 215

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net