Friday, December 07, 2007

XMLSerialization with multiple XMLRoot attributes

I recently had to construct an object hierarchy in order to produce an xml config file for a third party application. A lot of the config file could be constructed from boiler plate xml, so I needed a way to load in sections. The section I wanted to load was for a config element which occurs someway down the heirarchy:

sometag
core
object_definitions
object_type type="myType" plugin="myPlugin"
config
moretags
moretags
moretags
config
object_type
sometag
[Haven't worked out how to escape tags quickly, so I've stripped the brackets]
The following code shows how I created a static method in my config class to load this.

8 ///

9 /// Allows definition of all UI properties

10 ///

11 [Serializable]

12 [XmlRoot("config")]

13 public class ConfigureUIObjectConfig : ObjectConfigBase

14 {

15 public static ConfigureUIObjectConfig LoadUIConfig(string filePath)

16 {

17 System.IO.StreamReader sr=null;

18 ConfigureUIObjectConfig conf;

19 try

20 {

21

22 XmlSerializer xs = new XmlSerializer(typeof(ConfigObjects.ObjectTypes.ConfigureUIObjectConfig));

23

24 sr = new System.IO.StreamReader(filePath);

25 conf = (ConfigureUIObjectConfig)xs.Deserialize(sr);

26 }

27 catch (Exception)

28 {

29 throw;

30 }

31 finally

32 {

33 if (sr!=null)

34 sr.Close();

35 }

36

37 return conf;

38 }


I invoke it from what is normally the root class in my hierarchy in the constructor:

52 public ConfigFile()

53 {

54 //Add default object types

55 ConfigureUIObjectConfig uiConf = new ConfigureUIObjectConfig();

56 ObjectType obj = new ObjectType();

57 //obj.Config = uiConf;

58 obj.Config = ConfigureUIObjectConfig.LoadUIConfig("DefaultUIConfig.xml");//uiConf;

59 obj.Plugin = "UiConfiguratorPlugin";

60 obj.Type = "ConfigureUI";

61 this.Core.ObjectDefinitions.ObjectTypes.Add( obj);

62

63 }



The key to getting this to work is to decorate the ConfigureUIObjectConfig class with the [XmlRoot("config")] attribute. If you do not do this you will get an exception:

System.InvalidOperationException: <config xmlns=''> was not expected.


This eluded me at first as I assumed that I could only mark one class with the XmlRoot attribute, however, it appears that this does not matter in this instance.