C# Xml File Put It Back Into the Object

This article uses practical examples in order to demonstrate how to deserialize simple as well as complex (nested) XML into C# objects. The article presented two generic functions which allows XML to be deserialized into a C# Object, and converts a C# object into XML. In order to demonstrate how to use these functions, two examples were presented on how to work with simple XML data and complex hierarchical data. The article also mentioned the limitation of not being able to deserialize interafce types and nullable types, and also provided examples on how to overcome these drawbacks of the XmlSerializer.

  • Download PopulateObjectFromXML.zip - 12.3 MB

Introduction

This article uses practical examples in order to demonstrate how to deserialize simple as well as complex (nested) XML into C# objects.  For completeness, the article also demonstrates how to do the reverese i.e to convert a simple or complex C# object into XML.

Background

In some cases it can be much easier to work with a business object instance or a list of business object instances in C# than it is to traverse an XMLDocument object containing business information.  The source of the data may be from a 3rd party web service, a file exported from a legacy system, or even a SQL Server table column holding XML information.  This article shows a quick and simple way of converting the XML to objects and back to XML again.

Using the code

The sample code which accompanies this article can be downloaded here.

The Serializer.cs class contains two methods, namely Deserialize and Serialize.  The Deserialize method receives a string containing the xml to deserialize and returns an object of type T. Conversely, the Serialize method receives an object of type T and converts this into xml.

In both cases we are working with an object of type T which allows the client code to pass in objects of different types, making the two routines generic for serialization.

          using          System;          using          System.Collections;          using          System.IO;          using          System.Xml.Serialization;          namespace          TestHarness {          public          class          Serializer     {          public          T Deserialize<T>(string          input)          where          T :          class          {             System.Xml.Serialization.XmlSerializer ser =          new          System.Xml.Serialization.XmlSerializer(typeof(T));          using          (StringReader sr =          new          StringReader(input))             {          return          (T)ser.Deserialize(sr);             }         }          public          string          Serialize<T>(T ObjectToSerialize)         {             XmlSerializer xmlSerializer =          new          XmlSerializer(ObjectToSerialize.GetType());          using          (StringWriter textWriter =          new          StringWriter())             {                 xmlSerializer.Serialize(textWriter, ObjectToSerialize);          return          textWriter.ToString();             }         }     } }

Example 1

In this example we will convert a simple xml file holding customer details into a C# object instance.

simple object diagram

The xml data looks something like:

          <          Customer          >          <          CustomerID          >ALFKI<          /CustomerID          >          <          CompanyName          >Alfreds Futterkiste<          /CompanyName          >          <          ContactName          >Maria Anders<          /ContactName          >          <          ContactTitle          >Sales Representative<          /ContactTitle          >          <          Address          >Obere Str. 57<          /Address          >          <          City          >Berlin<          /City          >          <          PostalCode          >12209<          /PostalCode          >          <          Country          >Germany<          /Country          >          <          Phone          >030-0074321<          /Phone          >          <          Fax          >030-0076545<          /Fax          >          <          /Customer          >        

The following code snippet reads xml data from a file and creates a customer object by calling the Deserialize method, and passing it a customer type.

Serializer ser =          new          Serializer();          string          path =          string.Empty;          string          xmlInputData =          string.Empty;          string          xmlOutputData =          string.Empty;   path = Directory.GetCurrentDirectory() +          @"          \Customer.xml"; xmlInputData = File.ReadAllText(path);  Customer customer = ser.Deserialize<Customer>(xmlInputData); xmlOutputData = ser.Serialize<Customer>(customer)        

The Serialize method converts a customer object to XML.

Watch window on simple object data

Example 2

Complex object diagram

The above diagram shows a Customer object which has one or more Order object instances.  Each Order instance can have one or more Order Detail instances, and a given Order Detail instance can have one or more Product instances.

The abbreviated XML structure which is derived from the above object model is shown below.  Please refer to the sample code for the full XML.

          <          Customer          >          <          CustomerID          >ALFKI<          /CustomerID          >          <          CompanyName          >Alfreds Futterkiste<          /CompanyName          >          <          ContactName          >Maria Anders<          /ContactName          >          <          ContactTitle          >Sales Representative<          /ContactTitle          >          <          Address          >Obere Str. 57<          /Address          >          <          City          >Berlin<          /City          >          <          PostalCode          >12209<          /PostalCode          >          <          Country          >Germany<          /Country          >          <          Phone          >030-0074321<          /Phone          >          <          Fax          >030-0076545<          /Fax          >          <          Orders          >          <          Order          >          <          OrderID          >10643<          /OrderID          >          <          CustomerID          >ALFKI<          /CustomerID          >          <          EmployeeID          >6<          /EmployeeID          >          <          OrderDate          >1997-08-25T00:00:00<          /OrderDate          >          <          RequiredDate          >1997-09-22T00:00:00<          /RequiredDate          >          <          ShippedDate          >1997-09-02T00:00:00<          /ShippedDate          >          <          ShipVia          >1<          /ShipVia          >          <          Freight          >29.4600<          /Freight          >          <          ShipName          >Alfreds Futterkiste<          /ShipName          >          <          ShipAddress          >Obere Str. 57<          /ShipAddress          >          <          ShipCity          >Berlin<          /ShipCity          >          <          ShipPostalCode          >12209<          /ShipPostalCode          >          <          ShipCountry          >Germany<          /ShipCountry          >          <          Order_Details          >          <          Order_Detail          >          <          OrderID          >10643<          /OrderID          >          <          ProductID          >28<          /ProductID          >          <          UnitPrice          >45.6000<          /UnitPrice          >          <          Quantity          >15<          /Quantity          >          <          Discount          >2.5000000e-001<          /Discount          >          <          Product          >          <          ProductID          >28<          /ProductID          >          <          ProductName          >Rössle Sauerkraut<          /ProductName          >          <          SupplierID          >12<          /SupplierID          >          <          CategoryID          >7<          /CategoryID          >          <          QuantityPerUnit          >25 - 825 g cans<          /QuantityPerUnit          >          <          UnitPrice          >45.6000<          /UnitPrice          >          <          UnitsInStock          >26<          /UnitsInStock          >          <          UnitsOnOrder          >0<          /UnitsOnOrder          >          <          ReorderLevel          >0<          /ReorderLevel          >          <          Discontinued          >1<          /Discontinued          >          <          /Product          >          <          /Order_Detail          >          <          Order_Detail          >          <          OrderID          >10643<          /OrderID          >          <          ProductID          >39<          /ProductID          >          <          UnitPrice          >18.0000<          /UnitPrice          >          <          Quantity          >21<          /Quantity          >          <          Discount          >2.5000000e-001<          /Discount          >          <          Product          >          <          ProductID          >39<          /ProductID          >          <          ProductName          >Chartreuse verte<          /ProductName          >          <          SupplierID          >18<          /SupplierID          >          <          CategoryID          >1<          /CategoryID          >          <          QuantityPerUnit          >750 cc per bottle<          /QuantityPerUnit          >          <          UnitPrice          >18.0000<          /UnitPrice          >          <          UnitsInStock          >69<          /UnitsInStock          >          <          UnitsOnOrder          >0<          /UnitsOnOrder          >          <          ReorderLevel          >5<          /ReorderLevel          >          <          Discontinued          >0<          /Discontinued          >          <          /Product          >          <          /Order_Detail          >          <          /Order_Details          >          <          /Order          >          <          /Orders          >          <          /Customer          >        

The code below is similar to the snippet above, and deserializes nested Xml into a complex C# object.

Serializer ser =          new          Serializer();          string          path =          string.Empty;          string          xmlInputData =          string.Empty;          string          xmlOutputData =          string.Empty;   path = Directory.GetCurrentDirectory() +          @"          \CustOrders.xml"; xmlInputData = File.ReadAllText(path);  Customer customer2 = ser.Deserialize<Customer>(xmlInputData); xmlOutputData = ser.Serialize<Customer>(customer2);        

The screenshot below shows the contents of the customer2 object, and the data which has been populated through deserialization.   The customer, order, order details, and product have been applied to the complex object instance.

Watch window on the complex object data

Points of Interest

Interface Types

1. The XmlSerializer is unable to serialize interface types such as ICollection.  In the Customer.cs file if the following line is changed from :

          public          List<Order> Orders {          get;          set; }        

to

          public          ICollection<Order> Orders {          get;          set; }        

the following error is displayed :

Cannot serialize member TestHarness.Customer.Orders of type System.Collections.Generic.ICollection`1[[TestHarness.Order, TestHarness, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] because it          is          an          interface.        

In order to resolve this error the ICollection return type would need to be changed to a List type :

          public          List<Order> Orders {          get;          set; }        

or an array :

          public          Order[] Orders {          get;          set; }        

Nullable Types

2. When a property is declared as a nullable type such as an integer, and the value  from the input xml is a blank,  the nullable type is not recognised, and an attempt is made to save the null value to an int, resulting in the following error:

Input          string          was not          in          a correct format.        

In order to reproduce this error using the sample code, it is necessary to change the following line in the Order.cs file :

          public          int          ShipVia {          get;          set; }

to a nullable int :

          public          int? ShipVia {          get;          set; }

In the CustOrders.xml file please change the following on line 20 from :

          <          shipvia          >1<          /shipvia          >        

to a blank value as shown here...

          <          shipvia          >          <          /shipvia          >        

Running the application would reproduce this error :

Input          string          was not          in          a correct format.

In order to get around the problem of deserializing nullable types, the following code can be used in the Order.cs file.

          [          XmlIgnore]          public          int? ShipVia {          get;          set; }  [XmlElement("          ShipVia")]          public          string          ShipVia_Proxy {          get          {          return          ShipVia.HasValue ? ShipVia.ToString() :          string.Empty;     }          set          {          if          ( !string.IsNullOrEmpty(value))         {             ShipVia =          Int32.Parse(value);         }     } }        

The ShipViaproperty is prefixed with the [XmlIgnore] to exclude the property from serialization.  Instead, the ShipVia_Proxy string property is be used as an alternative to store a value whether it is a null or a none null.

The ShipVia_Proxy is prefixed with [XmlElement("ShipVia")] attribute in order to indicate to the XmlSerializer that the ShipVia element is to be mapped to ShipVia_Proxy instead of the ShipVia nullable property.  The overall effect is that if the ShipVia XML element is empty, a null is applied to theShipVia object property.

This is by no means the best approach for deserializing nullable types, however the solution is simple and quick to implement.

Conclusion

The article presented two generic functions which allows XML to be deserialized into a C# Object, and converts a C# object into XML.  In order to demonstrate how to use these functions, two examples were presented on how to work with simple xml data and complex hierarchical data.  The article also mentioned the limitation of not being able to deserialize interafce types and nullable types, and also provided examples on how to overcome these drawbacks of the XmlSerializer.

History

  • v 1.0 - 18:12GMT 2017-01-02

C# Xml File Put It Back Into the Object

Source: https://www.codeproject.com/Articles/1163664/Convert-XML-to-Csharp-Object

0 Response to "C# Xml File Put It Back Into the Object"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel