Last active
September 30, 2015 06:04
-
-
Save composite/ef848c7c43fdc61c5727 to your computer and use it in GitHub Desktop.
Improved Extension for Serialize XML with C#. Inspired from https://gist.github.com/martinnormark/2574972 and http://stackoverflow.com/questions/2404685/can-i-serialize-anonymous-types-as-xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Xml; | |
| using System.Xml.Linq; | |
| using Humanizer; | |
| namespace System.Xml | |
| { | |
| public static class XmlSerializerExtension | |
| { | |
| #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's 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's 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") | |
| ? "ResultElement" | |
| : arrayIndex != null | |
| ? arrayName + "_" + arrayIndex | |
| : name; | |
| } | |
| element = XmlConvert.EncodeName(element); | |
| var ret = new XElement(element); | |
| var type = input.GetType(); | |
| var props = type.GetProperties(); | |
| if (type.IsEnumerable()) | |
| return GetArrayElement(element, (IEnumerable)input, false); | |
| ret.Add(props.Select(p => | |
| { | |
| var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; | |
| var name = XmlConvert.EncodeName(p.Name); | |
| var prop = GetPropertyValue(input, p.Name); | |
| var val = pType.IsEnumerable() ? "array" : prop; | |
| var value = pType.IsEnumerable() | |
| ? GetArrayElement(p.Name, (IEnumerable) prop) | |
| : pType.IsSimpleType() || pType.IsEnum | |
| ? new XElement(name, val) | |
| : val.ToXml(name); | |
| return value; | |
| }).Where(v => v != null)); | |
| return ret; | |
| } | |
| #region helpers | |
| /// <summary> | |
| /// Gets the array element. | |
| /// </summary> | |
| /// <param name="element">The root element name.</param> | |
| /// <param name="input">The input object.</param> | |
| /// <param name="pluralize">pluralize element name or not.</param> | |
| /// <returns>Returns an XElement with the array collection as child elements.</returns> | |
| private static XElement GetArrayElement(string element, IEnumerable input, bool pluralize = true) | |
| { | |
| var names = XmlConvert.EncodeName(pluralize ? element.Pluralize() : element); | |
| var name = XmlConvert.EncodeName(element); | |
| XElement rootElement = new XElement(names); | |
| if (input != null) | |
| foreach (var val in input) | |
| { | |
| if(val == null) continue; | |
| XElement childElement = val.GetType().IsSimpleType() ? new XElement(name, val) : _ToXml(val, null, null, name); | |
| rootElement.Add(childElement); | |
| } | |
| return rootElement; | |
| } | |
| /// <summary> | |
| /// Gets the property value from any object. | |
| /// </summary> | |
| /// <param name="input">The any object.</param> | |
| /// <param name="name">The property name.</param> | |
| /// <returns>Property Value</returns> | |
| public static object GetPropertyValue(object input, string name) | |
| { | |
| ParameterExpression arg = Expression.Parameter(input.GetType(), "x"); | |
| Expression expr = Expression.Property(arg, name); | |
| var propertyResolver = Expression.Lambda(expr, arg).Compile(); | |
| return propertyResolver.DynamicInvoke(input); | |
| } | |
| #region .IsSimpleType | |
| /// <summary> | |
| /// Determines whether the specified type is simple type. | |
| /// it will Applies to : All Numerics, String, DateTime, enum, Guid | |
| /// </summary> | |
| /// <param name="type">The type.</param> | |
| /// <returns><c>true</c> if simple type is the specified type; otherwise, <c>false</c>.</returns> | |
| public static bool IsSimpleType(this Type type) | |
| { | |
| return type.IsPrimitive || WriteTypes.Contains(type); | |
| } | |
| #endregion .IsSimpleType | |
| /// <summary> | |
| /// Determines whether the specified type is enumerable. | |
| /// It does not apply to <see cref="System.String"/> | |
| /// </summary> | |
| /// <param name="type">The type.</param> | |
| /// <returns><c>true</c> if the specified type is enumerable; otherwise, <c>false</c>.</returns> | |
| public static bool IsEnumerable(this Type type) | |
| { | |
| return !WriteTypes.Contains(type) && typeof (IEnumerable).IsAssignableFrom(type); | |
| } | |
| #endregion helpers | |
| #endregion .ToXml | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Xml; | |
| using System.Xml.Linq; | |
| namespace System.Xml | |
| { | |
| public static class XmlSerializerExtension | |
| { | |
| #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's 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's 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") | |
| ? "ResultElement" | |
| : arrayIndex != null | |
| ? arrayName + "_" + arrayIndex | |
| : name; | |
| } | |
| element = XmlConvert.EncodeName(element); | |
| var ret = new XElement(element); | |
| var type = input.GetType(); | |
| var props = type.GetProperties(); | |
| if (type.IsEnumerable()) | |
| return GetArrayElement(element, (IEnumerable)input); | |
| ret.Add(props.Select(p => | |
| { | |
| var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; | |
| var name = XmlConvert.EncodeName(p.Name); | |
| var prop = GetPropertyValue(input, p.Name); | |
| var val = pType.IsEnumerable() ? "array" : prop; | |
| var value = pType.IsEnumerable() | |
| ? GetArrayElement(p.Name, (IEnumerable) prop) | |
| : pType.IsSimpleType() || pType.IsEnum | |
| ? new XElement(name, val) | |
| : val.ToXml(name); | |
| return value; | |
| }).Where(v => v != null)); | |
| return ret; | |
| } | |
| #region helpers | |
| /// <summary> | |
| /// Gets the array element. | |
| /// </summary> | |
| /// <param name="element">The root element name.</param> | |
| /// <param name="input">The input object.</param> | |
| /// <returns>Returns an XElement with the array collection as child elements.</returns> | |
| private static XElement GetArrayElement(string element, IEnumerable input) | |
| { | |
| var name = XmlConvert.EncodeName(element); | |
| XElement rootElement = new XElement(name + "Collection"); | |
| if (input != null) | |
| foreach (var val in input) | |
| { | |
| if(val == null) continue; | |
| XElement childElement = val.GetType().IsSimpleType() ? new XElement(name, val) : _ToXml(val, null, null, name); | |
| rootElement.Add(childElement); | |
| } | |
| return rootElement; | |
| } | |
| /// <summary> | |
| /// Gets the property value from any object. | |
| /// </summary> | |
| /// <param name="input">The any object.</param> | |
| /// <param name="name">The property name.</param> | |
| /// <returns>Property Value</returns> | |
| public static object GetPropertyValue(object input, string name) | |
| { | |
| ParameterExpression arg = Expression.Parameter(input.GetType(), "x"); | |
| Expression expr = Expression.Property(arg, name); | |
| var propertyResolver = Expression.Lambda(expr, arg).Compile(); | |
| return propertyResolver.DynamicInvoke(input); | |
| } | |
| #region .IsSimpleType | |
| /// <summary> | |
| /// Determines whether the specified type is simple type. | |
| /// it will Applies to : All Numerics, String, DateTime, enum, Guid | |
| /// </summary> | |
| /// <param name="type">The type.</param> | |
| /// <returns><c>true</c> if simple type is the specified type; otherwise, <c>false</c>.</returns> | |
| public static bool IsSimpleType(this Type type) | |
| { | |
| return type.IsPrimitive || WriteTypes.Contains(type); | |
| } | |
| #endregion .IsSimpleType | |
| /// <summary> | |
| /// Determines whether the specified type is enumerable. | |
| /// It does not apply to <see cref="System.String"/> | |
| /// </summary> | |
| /// <param name="type">The type.</param> | |
| /// <returns><c>true</c> if the specified type is enumerable; otherwise, <c>false</c>.</returns> | |
| public static bool IsEnumerable(this Type type) | |
| { | |
| return !WriteTypes.Contains(type) && typeof (IEnumerable).IsAssignableFrom(type); | |
| } | |
| #endregion helpers | |
| #endregion .ToXml | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment