Click here to Skip to main content
Licence CPOL
First Posted 9 Aug 2010
Views 11,083
Downloads 210
Bookmarked 16 times

Generic/Dynamic XML file handling using Reflection and C#

By | 18 Aug 2010 | Article
This article describes how to read XML files dynamically and as generic as possible using .NET Reflection.

Introduction

Consider an XML file that contains tags representing classes in your code, each of these classes having their own attributes. There is no specific order for these tags to be listed, and sometimes, some tags will not be listed within the XML file. How would you read such a file without the need to hard-code those attributes, or use switch or if statements?

This article will demonstrate how to do that without the need to hard-code anything using System.Reflection methods.

Using the Code

Consider the following XML file, which represents the following class structure: a class Vehicle that is a parent class for the child classes Aircraft, Car, Bus, Motorcycle, and Ship representing different types of vehicles, each having its own attributes.

<Vehicle>  
  <Aircraft>
      <Vehicle vehicleType="Presidential" Id="1" 
         Speed="800" Altitude="20000" NumberOfEngines="2" />
  </Aircraft>
  <Car> 
      <Vehicle vehicleType="None" Id="2" Speed="280" />
  </Car>
  <Car>
      <Vehicle vehicleType="Private" Id="3" Speed="220" />
  </Car>
  <Aircraft>
      <Vehicle vehicleType="Private" Id="4" 
         Speed="790" Altitude="30900" NumberOfEngines="4" />
  </Aircraft>
  <Bus>
      <Vehicle vehicleType="Public" Id="5" 
         Speed="150" NumberOfPassengers="60" />
  </Bus>
  <Motorcycle>
      <Vehicle vehicleType="Private" Id="6" 
             Speed="300" Racer="true" />
  </Motorcycle>
  <Motorcycle>
      <Vehicle vehicleType="Government" Id="7" 
            Speed="180" Racer="false" />
  </Motorcycle>
  <Bus>
      <Vehicle vehicleType="Government" Id="8" 
           Speed="190" NumberOfPassengers="48" />
  </Bus>
  <Ship>
      <Vehicle vehicleType="None" Id="9" 
            Speed="50" Weight="10000" Steam="false" />
  </Ship>
</Vehicle>

Now, we need to read this XML file and construct an object for each vehicle node and then save all of these objects in some data structure.

I used a dictionary of DataElements as follows:

// A dictionary that represents data read from the XML file
private readonly IDictionary<int, DataElement> vehicleDictionary = 
                                  new Dictionary<int, DataElement>();

where each DataElement contains two properties: one for the VehicleType and the other for the BaseVehicle object, as follows:

public class DataElement
{
    /// <summary>
    /// The BaseVehicle object indicating whether this
    /// element is a car, bus, aircraft, motorcycle or a ship.
    /// </summary>
    public BaseVehicle Vehicle
    {
        get;
        set;
    }

    /// <summary>
    /// The type of the vehicle indicated in VehicleType enumerator class.
    /// </summary>
    public VehicleType VehicleType
    {
        get;
        set;
    }
}

The VehicleType is an Enum that represents types of vehicles such as presidential, private, public etc.

Now for the core of this article. I used an XmlDocument object to access the XML file and carry out XML operations on it. To use that, we need to first load the XML file, and then read all tags included within the <Vehicle> tag.

// Used to access the XML file and carry out XML operations
XmlDocument doc = new XmlDocument();
try
{
    doc.Load("Vehicles.xml");
}
catch (Exception)
{
    throw new Exception("File not found.");
}

// Holds all tags existing inside the main tag "Vehicle"
// i.e. holds all nodes in the XML file in their
// original XML format
XmlNodeList temp = doc.GetElementsByTagName("Vehicle").Item(0).ChildNodes;

After that, I used an Assembly object (an object that contains the intermediate code, resources, and the metadata for a certain type of class, and is available under the System.Reflection namespace) to maintain the assembly of BaseVehicle.

// Used to hold all details of "GenericXML.Vehicle" including its child classes
Assembly asm = typeof(BaseVehicle).Assembly;

After that, I loop on every tag within the XmlDocument object, performing the following:

  • Getting the Type of the corresponding class for the current node name:
  • // Determines the type of the current node name
    // by searching in the assembly object "asm"
    Type tp = asm.GetType("GenericXML.Vehicle." + node.Name);
  • Getting all vehicles within the current node (of the current type):
  • // The vehicle nodes inside the current "type" node
    XmlNodeList itemsOfType = node.ChildNodes;
  • Looping on those nodes one by one, while automatically creating objects to be used to fill the dictionary. Those objects are still empty, i.e., their attributes are not set, so I'll show now how to determine those values:
  • // An automatically initiated object of the current type
    object obj = Activator.CreateInstance(tp); 
    DataElement tempElement = new DataElement
                      {
                          // Set the VehicleType by converting from string (in XML file) 
                          //to corresponding Enum type
                          VehicleType = (VehicleType)Enum.Parse(typeof (VehicleType),
                                         itemsNode.Attributes["vehicleType"].Value),
                                         Vehicle = (BaseVehicle)obj
                      };

For setting the suitable attributes for each object created, I used Reflection again, but this time to access class attributes and have the accessibility to set them as well. To do that, I used the GetProperty().SetValue() method.

// Set the value to the value mentioned in the XML file after conversion
// from string to suitable type
tp.GetProperty(att.Name).SetValue(tempElement.Vehicle, Convert.ChangeType
                (att.Value, tp.GetProperty(att.Name).PropertyType), null);

Points of Interest

Now, the thing you should mind is the naming of the attributes in the XML file; names must match with, taking in mind, the case of letters. Either that, or just convert the attribute names to lower (or upper) case and compare.

Please feel free to inquire about anything that is not clear enough.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mohamed Amr El Sisi

Engineer

Egypt Egypt

Member

Follow on Twitter Follow on Twitter
I graduated Computer Engineering - Cairo University in 2010 and currently I'm a software development engineer at Mentor Graphics Egypt.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
General[My vote of 2] thanks for effort Pinmemberjaan33us7:17 9 Aug '10  
GeneralRe: [My vote of 2] thanks for effort PinmemberMohamed Amr El Sisi12:11 9 Aug '10  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120515.1 | Last Updated 18 Aug 2010
Article Copyright 2010 by Mohamed Amr El Sisi
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid