
oxm
OXM is a framework for transforming .NET objects from/to XML. It features:
- Full control over the generated XML.
- POCO approach i.e. no attributes to pollute your domain entities.
- Fluent DSL for defining the mapping.
- Strongly typed/refactor-friendly.
- No reflection.
Quick Start
Let's convert the simple class Person to the XML described below. Notice that we chose to serialize the Name property to an attribute and the Age property to an XML element to showcase the flexibility of the framework.
public class Person
{ // <Person name="John Smith">
public string Name { get; set; } // <Age>12</Age>
public int Age { get; set; } // </Person>
}
For that we have to write a mapping class that defines the transformation rules between the two forms.
``` public class PersonMap : RoolElementMap { Person person = new Person();
public PersonMap()
{
Map(o => o.Name).ToAttribute("name", true)
.Set(v => person.Name = v)
.Converter(new StringConverter());
Map(o => o.Age).ToSimpleElement("Age", true)
.Set(v => person.Age = v)
.Converter(new Int32Converter());
}
protected override Person Return()
{
return person;
}
public override XName Name
{
get { return "Person"; }
}
} ```
The PersonMap
class inherits from the RootElementMap
because it's going to be the root element in the XML. Root elements are special elements in XML. Otherwise, for any other element you would use ClassMap
.
The DSL is mostly self explanatory. The constructor defines the mapping declaratively for each property. The Set method defines how to set the property when converting from XML. The Converter method specifies the converter that converts the property value from and to XML string. The framework defines many converters for common types (like string, int, etc) but it's very easy to define your own to customize the serialization of dates for example.
That's it. The following test explains how to execute the conversion from and to XML.
```
[Test]
public void PersonMap()
{
var person = new Person() { Name = "John Smith", Age = 12 };
var map = new PersonMap();
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
map.WriteXml(writer, person);
}
Person person2;
using (var reader = doc.CreateReader())
{
person2 = map.ReadXml(reader);
}
Assert.AreEqual(person.Name, person2.Name);
Assert.AreEqual(person.Age, person2.Age);
} ```
Non Default Constructor
Ok. Let's move to more advanced examples that showcase the advantages of OXM over the .NET attribute based serialization.
Let's assume you decide to design the person entity to have a constructor that takes the 'Name' property.
public class Person
{
public string Name { get; private set; } // <Person name="John Smith">
public int Age { get; set; } // <Age>12</Age>
// </Person>
public Person(string name)
{
Name = name;
}
}
This will, of course, removes the default constructor. The problem is that you cannot now initialize the entity without first parsing the content of the Person element.
The attribute based approach of the .NET framework will struggle with entities that don't provide a default constructor and uses a special HACK to initialize these entities for de-serialization by using http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx'>FormatterServices.GetUninitializedObject
Method which bypasses all constructors. This solution will not be good if you had logic in the non-default constructor which will be bypassed.
OXM, on the other hand, handles this case naturally using the following mapping.
``` public class PersonMap : RoolElementMap { string name; int age;
public PersonMap()
{
Map(o => o.Name).ToAttribute("name", true)
.Set(v => name = v)
.Converter(new StringConverter());
Map(o => o.Age).ToSimpleElement("Age", true)
.Set(v => age = v)
.Converter(new Int32Converter());
}
protected override Person Return()
{
return new Person(name) { Age = age };
}
public override XName Name
{
get { return "Person"; }
}
} ```
All we did is modify the Set methods to set the properties individually and the use the result in the Return method to initialize and return the entity.
More Scenarios
Of course the framework handles many other scenarios for solving the impedance mismatch between Xml and OO such as complex types, implicit collections, Object references, Element and Attribute orders, and others. Please download the code and look at the tests for more examples.
Where does OXM come from?
OXM design was influenced by principle of Object-Relational Mapping (ORM) since serializing objects to XML format is identical in principle to serializing to the database relational format. Moreover, mapping to XML is easier than mapping to a relational structure since the impedance mismatch less because XML for example allows complex members and collections and relational database do not.
The mapping DSL was inspired by the http://fluentnhibernate.org/'>FluentNhibernate
DSL which is equivalent to OXM in the ORM world.
Project Information
- License: MIT License
- 13 stars
- hg-based source control
Labels:
xml
xmlserialization
xmlbinding
.net
csharp