Can I serialize anonymous types as xml?

I realized that anonymous types are marked by a private compiler, and properties are read-only. Is there a way to serialize them in xml (without deserialization)? It works with JSON , how can I do this with XML?

+50
xml serialization anonymous-types
Mar 08
source share
5 answers

Sorry, you can’t. The XML serializer pretty much just serializes the public read-write types.




Please note that my answer is about using an XML serializer. You can succeed with other serializers, in particular, try it with the Data Serializer.

+26
Mar 08
source share

Something like this should get you started ...

class Program { static void Main(string[] args) { var me = new { Hello = "World", Other = new { My = "Object", V = 1, B = (byte)2 } }; var x = me.ToXml(); } } public static class Tools { private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid), }; public static bool IsSimpleType(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } public static XElement ToXml(this object input) { return input.ToXml(null); } public static XElement ToXml(this object input, string element) { if (input == null) return null; if (string.IsNullOrEmpty(element)) element = "object"; element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = from prop in props let name = XmlConvert.EncodeName(prop.Name) let val = prop.GetValue(input, null) let value = prop.PropertyType.IsSimpleType() ? new XElement(name, val) : val.ToXml(name) where value != null select value; ret.Add(elements); } return ret; } } 

... result xml ...

 <object> <Hello>World</Hello> <Other> <My>Object</My> <V>1</V> <B>2</B> </Other> </object> 
+68
Mar 08 '10 at 21:43
source share

Thanks, great job @Matthew and @Martin.

I made a couple of modifications to accommodate Nullables and Enums. I also changed it so that the elements of the array were named according to the name of the property + index.

Here is the code if anyone is interested

 public static class ObjectExtensions { #region Private Fields private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid), }; #endregion Private Fields #region .ToXml /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <returns>Returns the object as it XML representation in an XElement.</returns> public static XElement ToXml(this object input) { return input.ToXml(null); } /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <param name="element">The element name.</param> /// <returns>Returns the object as it XML representation in an XElement.</returns> public static XElement ToXml(this object input, string element) { return _ToXml(input, element); } private static XElement _ToXml(object input, string element, int? arrayIndex = null, string arrayName = null) { if (input == null) return null; if (String.IsNullOrEmpty(element)) { string name = input.GetType().Name; element = name.Contains("AnonymousType") ? "Object" : arrayIndex != null ? arrayName + "_" + arrayIndex : name; } element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = props.Select(p => { var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; var name = XmlConvert.EncodeName(p.Name); var val = pType.IsArray ? "array" : p.GetValue(input, null); var value = pType.IsArray ? GetArrayElement(p, (Array)p.GetValue(input, null)) : pType.IsSimpleType() || pType.IsEnum ? new XElement(name, val) : val.ToXml(name); return value; }) .Where(v=>v !=null); ret.Add(elements); } return ret; } #region helpers /// <summary> /// Gets the array element. /// </summary> /// <param name="info">The property info.</param> /// <param name="input">The input object.</param> /// <returns>Returns an XElement with the array collection as child elements.</returns> private static XElement GetArrayElement(PropertyInfo info, Array input) { var name = XmlConvert.EncodeName(info.Name); XElement rootElement = new XElement(name); var arrayCount = input == null ? 0 : input.GetLength(0); for (int i = 0; i < arrayCount; i++) { var val = input.GetValue(i); XElement childElement = val.GetType().IsSimpleType() ? new XElement(name + "_" + i, val) : _ToXml(val, null, i, name); rootElement.Add(childElement); } return rootElement; } #region .IsSimpleType public static bool IsSimpleType(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } #endregion .IsSimpleType #endregion helpers #endregion .ToXml } 
+24
Jun 25 '11 at 8:12
source share

My own version of the excellent work of @Matthew and @Martin: arrays of enumerations and the concept of arrays in a generalized form in IEnumerable are now supported to also support all kinds of collections.

 public static class ObjectExtensions { /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <returns>Returns the object as it XML representation in an XElement.</returns> public static XElement ToXml2(this object input) { return input.ToXml2(null); } /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <param name="element">The element name.</param> /// <returns>Returns the object as it XML representation in an XElement.</returns> public static XElement ToXml2(this object input, string element) { return _ToXml(input, element); } private static XElement _ToXml(object input, string element, int? arrayIndex = null, string arrayName = null) { if (input == null) return null; if (String.IsNullOrEmpty(element)) { string name = input.GetType().Name; element = name.Contains("AnonymousType") ? "Object" : arrayIndex != null ? arrayName + "_" + arrayIndex : name; } element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = props.Select(p => { var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; var name = XmlConvert.EncodeName(p.Name); var val = pType.IsArray ? "array" : p.GetValue(input, null); var value = pType.IsEnumerable() ? GetEnumerableElements(p, (IEnumerable)p.GetValue(input, null)) : pType.IsSimpleType2() || pType.IsEnum ? new XElement(name, val) : val.ToXml2(name); return value; }) .Where(v=>v !=null); ret.Add(elements); } return ret; } #region helpers private static XElement GetEnumerableElements(PropertyInfo info, IEnumerable input) { var name = XmlConvert.EncodeName(info.Name); XElement rootElement = new XElement(name); int i = 0; foreach(var v in input) { XElement childElement = v.GetType().IsSimpleType2() || v.GetType().IsEnum ? new XElement(name + "_" + i, v) : _ToXml(v, null, i, name); rootElement.Add(childElement); i++; } return rootElement; } private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid), }; public static bool IsSimpleType2(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } private static readonly Type[] FlatternTypes = new[] { typeof(string) }; public static bool IsEnumerable(this Type type) { return typeof(IEnumerable).IsAssignableFrom(type) && !FlatternTypes.Contains(type); } #endregion } 
+3
Mar 10 '15 at 10:31
source share

The answer below handles IEnumerables in the form I needed and will do the following:

 new { Foo = new[] { new { Name = "One" }, new { Name = "Two" }, }, Bar = new[] { new { Name = "Three" }, new { Name = "Four" }, }, } 

in it:

 <object> <Foo><Name>One</Name></Foo> <Foo><Name>Two</Name></Foo> <Bar><Name>Three</Name></Bar> <Bar><Name>Four</Name></Bar> </object> 

So, here you are, another version of Matthew's answer:

 public static class Tools { private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(Enum), typeof(DateTime), typeof(DateTime?), typeof(DateTimeOffset), typeof(DateTimeOffset?), typeof(int), typeof(int?), typeof(decimal), typeof(decimal?), typeof(Guid), typeof(Guid?), }; public static bool IsSimpleType(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } public static object ToXml(this object input) { return input.ToXml(null); } public static object ToXml(this object input, string element) { if (input == null) return null; if (string.IsNullOrEmpty(element)) element = "object"; element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); if (input is IEnumerable && !type.IsSimpleType()) { var elements = (input as IEnumerable<object>) .Select(m => m.ToXml(element)) .ToArray(); return elements; } else { var props = type.GetProperties(); var elements = from prop in props let name = XmlConvert.EncodeName(prop.Name) let val = prop.GetValue(input, null) let value = prop.PropertyType.IsSimpleType() ? new XElement(name, val) : val.ToXml(name) where value != null select value; ret.Add(elements); } } return ret; } } 
+2
Mar 16 '16 at 10:25
source share



All Articles