Skip to content

Instantly share code, notes, and snippets.

@composite
Last active September 30, 2015 06:04
Show Gist options
  • Select an option

  • Save composite/ef848c7c43fdc61c5727 to your computer and use it in GitHub Desktop.

Select an option

Save composite/ef848c7c43fdc61c5727 to your computer and use it in GitHub Desktop.
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
}
}
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