How to override XML elements and attributes at run-time

by Dominic Zukiewicz 24. March 2008 19:08

Firstly, we'll start with a nice simple bit of XML:

<Customer>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
</Customer>

Think of the situation. You've got your business classes, which serialize to XML. Great! You've named your properties to meaningful names so the XML that comes out is correct for your customer, or you've used the XmlRoot, XmlElement & XmlAttribute attributes to override this, everything is going smoothly.

All of a sudden - "We need to modify the XML very slighty so that we have to rename the elements for certain customers.". You could use XSLT, BizTalk (quite expensive!) OR ..... you could use a hidden away group of classes to help you rename elements and attributes when serializing.

So lets start with some code to create the Customer class. Note I'm using .NET 3.5 syntax, although this functionality is available in 2.0:

public class Customer 
{
   public Customer() {}
 
   public string FirstName { get; set; } 
   public string LastName { get; set; }
}

Okay, and so if you serialize this, you've get the example at the top of the page, with code similar to:

//.NET 2.0 this is the same as c.FirstName = "John"; c.LastName = "Smith";
Customer c = new Customer() { FirstName = "John", LastName = "Smith" };
 
XmlSerializer xmlSer = new XmlSerializer(c.GetType()); 
MemoryStream ms = new MemoryStream(); 
xmlSer.Serialize(ms,c); 
string xml = Encoding.Default.GetString(ms.ToArray());

Now, your customer calls you and says "actually we want Partner A to rename the FirstName element to "ChristianName", and the LastName element to "Surname". You put the phone down, they call back and say "Oh, and Partner B wants to rename FirstName to just Name, and LastName to FinalName.". Phone goes down .... Ring ring! "Oh - and we need Partner C to name FirstName to OXF435AAS and LastName of EERDS335D.".

Okay, so don't panic. We can use a bunch of classes to help us rename this.

So basic steps:

  1. Use the XmlElementAttribute class to store your new element name.
  2. Use the XmlAttributes class to store the new XmlElementAttribute. This class stores a collection of all the XML related attributes on a class.
  3. Use an XmlAttributeOverrides class (or the same one if repeating) to tell the serializer what it should covert from and to, e.g. FirstName --> ChristianName.
  4. Repeat 1,2 and 3 until there are no more attributes to override.
  5. Pass the XmlAttributeOverrides to the XmlSerializer to do the conversion for us.

Before doing that, I've simplified the XmlSerializer into its own method to make it much easier to serialize XML:

protected string ConvertTypeToString(object graph, XmlAttributeOverrides overrides) 
{ 
   XmlSerializer xmlSer = new XmlSerializer(graph.GetType(), overrides); 
   MemoryStream ms = new MemoryStream(); 
   xmlSer.Serialize(ms,graph); 
   string xml = Encoding.Default.GetString(ms.ToArray()); 
   return xml; 
} 

So remember - Create an XmlElementAttribute class to hold the NEW name, add it to the XmlAttributes, add the attributes to the overrides, then pass the XmlAttributeOverrides class.

//Rename the c.FirstName to c.ChristianName 
XmlElementAttribute newName = new XmlElementAttribute("ChristianName"); 
 
XmlAttributes attrCollection = new XmlAttributes(); 
attrCollection.XmlElements.Add(newName); 
 
XmlAttributeOverrides overrideAtt = new XmlAttributeOverrides(); 
overrideAtt.Add(c.GetType(), "FirstName", attrCollection); 
 
return ConvertTypeToString(c, overrideAtt);

And this will output:

<Customer>
<ChristianName>John</ChristianName>
<LastName>Smith</LastName>
</Customer>

Okay, so thats how to rename 1 element, so here's how to rename many:

//Rename the c.FirstName to c.ChristianName 
 
XmlElementAttribute newFirstName = new XmlElementAttribute("ChristianName"); 
XmlAttributes attrCollection = new XmlAttributes(); 
attrCollection.XmlElements.Add(newFirstName); 
 
//Rename the c.LastName to c.Surname
XmlElementAttribute newSurname = new XmlElementAttribute("Surname"); 
XmlAttributes attrCollection2 = new XmlAttributes(); 
attrCollection2.XmlElements.Add(newSurname); 
 
XmlAttributeOverrides overrideAtt = new XmlAttributeOverrides(); 
overrideAtt.Add(c.GetType(), "FirstName", attrCollection); 
overrideAtt.Add(c.GetType(), "LastName", attrCollection2); 
return ConvertTypeToString(c, overrideAtt); 

So its easy to see how simple this can be. In practice, I found that creating an abstract class with the ConvertTypeToString method implemented and an abstract "TransformCustomer" method which was specific to the customer. Then at runtime, you can use a switch statement to use the class you want to. If you want to be more clever, you can use Reflection to make this decision for you.

And this will output:
<Customer>
<ChristianName>John</ChristianName>
<Surname>Smith</Surname>
</Customer>

Tags:

Xml

Powered by BlogEngine.NET 1.5.0.7
Theme by Interakting

Interakting

A full service digital agency offering online strategy, design and usability, systems integration and online marketing services that deliver real business benefits and ensure your online objectives are met.

Calendar

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar