Click here to Skip to main content
15,881,281 members
Articles / Programming Languages / XML
Article

XmlReflector

Rate me:
Please Sign up or sign in to vote.
3.73/5 (6 votes)
9 Oct 2008Ms-PL6 min read 24.9K   182   39   2
This library provides XML based dynamic object mapping which can be used while designing dynamic data, configuration and business layers.

Introduction

The use of XML for the right purpose and at the right place can help developers very much. WPF (Windows Presentation Foundation), WWF (Windows Workflow Foundation), and WCF (Windows Communication Foundation) are some of the technologies which make use of it for the right purpose and at the right place.

When I first started playing with my LEGO set when I was about 5 years old, I was plugging pieces from the same kit or even from others, to create new toys and to play with them. It was a good decision by my father not to buy me a new toy every time I needed one, but instead give me a set with which I could create my toys, thus decreasing the costs :)

After I met XML, I said to myself: "Let's connect the pieces together and create new toys". One of these toys was the "Friendship of XML and Reflection". It is a toy with two main pieces: an XmlLayer, and an Element where XmlLayer is the base on which you build your toys and the Element is the base from which you create new pieces or toys.

Deliverables

I have included the source code for the library along with a demo application. I will add the documentation and the Unit Test code as soon as I find the time and energy (I am currently working on four projects at the same time).

Design

The major entities of this design are:

pic_BaseElements.PNG

  • Element - A custom XmlElement base class which provides Dictionary, List, and ValueConversion support.
  • XmlLayer - A custom XmlDocument class which provides Reflection and element indexing support (without DTD).
  • Parameter - A strongly typed Element class which is designed to store information that can be called as a Parameter (e.g., algorithm parameters, connection string parameters).
  • Property - A strongly typed Element class which is designed to store information for an entity. For me, an entity is something which can be defined with properties. These properties can be hardcoded like a Student entity having name, age, and class properties, but each of them is stored as a single property in the code accompanying this article.

XmlLayer

The XmlLayer class provides Reflection support to create strongly-typed Element(s).

pic_XmlLayer.PNG

C#
public class XmlLayer : XmlDocument
{
   public void RegisterType(string localNameOrAlias, Type type);
   public override XmlElement CreateElement(string prefix, 
                   string localName, string namespaceURI);
   public override XmlElement GetElementById(string elementId);
   private void ReadElements(XmlReader reader);
   protected virtual Element OnDefaultElementNeeded(string prefix, 
                     string localName, string namespaceURI);
}
  • RegisterType registers an Element having the specified local name or alias with the XmlLayer. Let's say you have an XML file containing elements prm, top, and connection_string. You can create your custom Elements such as Parameter, Topic, and ConnectionString, each inheriting from the Element class, and register them with the aliases prm, top, and connection_string. When the XmlLayer is loaded from this XML file, it will automatically create your custom wlements instead of simple XmlElement(s), when it hits these aliases.
  • CreateElement overrides the XmlElement.CreateElement(....) base method and creates custom Element(s) instead of the default XmlElement. It checks whether the local name was registered with a custom Element type. If so, it then creates the instance of that type through Reflection.
  • GetElementById overrides the XmlElement.GetElementById(....) base method. It looks up the elements from an internal HashTable instance containing WeakReference(s) to created elements. This removes the necessity of using DTDs for element lookup.
  • ReadElements reads only the registered elements from a XmlReader. It skips the non-registered ones, preserving the element hierarchy and attributes. It is basically there to filter out unwanted elements which should not be part of our custom Element(s). It is called from the LoadRegisteredTypes method which reads an XML stream/file sequentially without reading the whole stream/file at once into memory. You can parse a huge XML file, extracting only what you need.
  • OnDefaultElementNeeded is called from the overridden CreateElement method to create custom base element types in case a non-registered element is to be created. You can override this method in your own XmlLayer class to create base/default elements of type MyBaseElement, for example.

Element

The Element class provides Dictionary, List, and ValueConversion support for strongly-typed Element(s).

pic_Element.PNG

C#
public class Element: XmlElement, ILayerList, ILayerDictionary, IUnique, IEnumerable
{
   public override string InnerText{ get; set; }
   public new string Value { get; set; }
   protected virtual void SetValueCore(string newValue)

   public void SetValue(System.Int32 value)
   public void SetValue(System.Double value)
   public void SetValue(System.DateTime value)
   public void SetValue(System.Enum value)
   .
   .
   .

   public System.Int32 ValueAs(System.Int32 defaultValue)
   public System.Double ValueAs(System.Double defaultValue)
   public System.DateTime ValueAs(System.DateTime defaultValue)
   public TEnum ValueAsEnum<TEnum>(TEnum defaultValue)
   .
   .
   .

   protected Element GetChildElement(string elementOrPath, bool createIfNotExists)
   protected virtual IEnumerable<TLayerElement> OfType<TLayerElement>() 
                     where TLayerElement : Element
}
  • InnerText overrides the XmlElement.InnerText base property. It calls the SetValueCore virtual method. The idea behind is to give custom elements the ability to detect value changes and fire events. The Element class also hides the Value property, and calls the InnerText property's get and set accessors. All these centralize the value change control to one method: SetValueCore.
  • GetChildElement gets an element from a backslash separated path of element names (e.g., \Books\Book\Author). The element returned is the last element in the path, which is Author. This method optionally creates the element if it does not exist.
  • OfType<TLayerElement>() filters the child elements based on a specified type.

Property

The Property class represents a single property of an entity. It is contained in a Properties element which is a collection of properties.

pic_Prop.PNG

C#
public class Property: Element, System.ComponentModel.INotifyPropertyChanged
{
   protected override void SetValueCore(string newValue)
   private void NotifyPropertyChanged(string property)
}
  • SetValueCore overrides the base class method to notify subscribers of the changes to the value of the property.
  • NotifyPropertyChanged informs the subscribers of the System.ComponentModel.INotifyPropertyChanged.PropertyChanged event. It also calls the OnPropertyChanged method of the Properties collection which owns this property.

Properties

The Properties class represents a collection of properties. When an entity such as class Student: Element is created, the Properties collection can be appended to it to provide easy property creation and clean persistence.

pic_Properties.PNG

C#
public class Properties : Element, ILayerList<Property>>
{
   public event EventHandler<PropertyChangedEventArgs> PropertyChanged

   public new Property this[string name] { get; set; }
   public bool HasProperty(string name)
   protected virtual Property GetProperty(string name)
   protected internal virtual void OnPropertyChanged(string property)
}
  • PropertyChanged is the event which is fired when the value of a property in the collection changes.
  • this[string name] gets the property with the specified name. By default, creates the property if it does not exist, providing dynamic property support at runtime.
  • HasProperty checks whether a property with the specified name exists in the collection.
  • OnPropertyChanged is called from a property contained in the collection when its value changes.

Parameter

The Parameter class represents a single parameter which stores a numerical or textual value. It is basically a value consumed in a measurement or calculation.

pic_Parameter.PNG

C#
[TypeConverter(typeof(ParameterConverter))]
public class Parameter : Element, System.ComponentModel.ICustomTypeDescriptor
{
   public string Description { get; set; }
   public string Alias{ get; set; }
   protected virtual PropertyDescriptorCollection FilterProperties(
                     PropertyDescriptorCollection pdc)
}
  • Description is the custom information for a parameter which provides additional information besides the name of the parameter.
  • Alias is the custom name for a parameter. Let's say, you receive an algorithm specification where you have an input parameter named TFTMin and you want to display a more meaningful name to the user via the GUI to modify this parameter. This is exactly the reason to have an alias for a parameter.
  • FilterProperties filters the properties to be displayed when a parameter is attached to a .NET PropertyDescriptor control, which I use for its simplicity.

Parameters

The Parameters class represents a collection of parameters and sub-parameter collections.

pic_Parameters.PNG

C#
[TypeConverter(typeof(ParameterCollectionConverter))]
public class Parameters : Element, ILayerList<parameter>, 
       System.ComponentModel.ICustomTypeDescriptor
{
   public new Parameter this[string name] { get; }
   public virtual Parameter CreateParameter(string name))
   public Parameters GetSubset(string name)
   public TParameters GetSubset<tparameters>() where TParameters : Parameters
   protected virtual PropertyDescriptorCollection 
             FilterProperties(PropertyDescriptorCollection pdc)
}
  • this[string name] gets the parameter with the specified name.
  • CreateParameter creates a parameter with the specified name.
  • GetSubset gets the sub-parameters collection with the specified name.
  • GetSubset<TParameters> gets the strongly-typed sub-parameters collection with the specified name.
  • FilterProperties filters the properties to be displayed when a parameter collection is attached to a .NET PropertyDescriptor control, which I use for its simplicity.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer (Senior)
Turkey Turkey
I am a software developer who likes to code his ideas in his freetime. I like playing strategy games and going to spearfishing.

Comments and Discussions

 
Questioncan you provide your code?? Pin
JLKEngine00830-Sep-08 0:40
JLKEngine00830-Sep-08 0:40 
AnswerRe: can you provide your code?? [modified] Pin
AFSEKI30-Sep-08 1:05
AFSEKI30-Sep-08 1:05 

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

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