Created
December 3, 2017 16:59
-
-
Save vladris/d3d9c7ab5ba790f7928997f6b1b6cb21 to your computer and use it in GitHub Desktop.
Extension method for XElement to deserialize into a dynamic object
This file contains 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.Generic; | |
using System.Dynamic; | |
using System.Xml.Linq; | |
/// <summary> | |
/// Provides extension method for XElement to deserialize to a dynamic object | |
/// | |
/// The element's attributes will be stored as properties on the dynamic object. | |
/// The child elements will also be stored as properties on the dynamic object with the | |
/// following convention: if the element has a single child with a given name, that | |
/// child will appear as a property with the element's name. If multiple children have | |
/// the same name, they will be stored as a List of objects in a property with their name. | |
/// | |
/// By default, the name of the element will be stored into the Name property, the value | |
/// of the element will be stored into the Value property, and a method to enumerate over | |
/// children will be provided as Elements(). The names can be customized if they conflict | |
/// with the content of the XML. | |
/// </summary> | |
static class XElementDynamicDeserializer | |
{ | |
/// <summary> | |
/// Deserializes XElement into a dynamic object. | |
/// </summary> | |
/// <param name="element">XElement to deserialize</param> | |
/// <param name="nameProperty">Property name for the name of the element</param> | |
/// <param name="valueProperty">Property name for the value of the element</param> | |
/// <param name="elementsMethod">Method name for the method to enumerate child elements</param> | |
/// <returns>Dynamic object</returns> | |
public static dynamic ToDynamic( | |
this XElement element, | |
string nameProperty = "Name", | |
string valueProperty = "Value", | |
string elementsMethod = "Elements") | |
{ | |
var result = new ExpandoObject() as IDictionary<string, object>; | |
// Node name and value | |
result[nameProperty] = element.Name.LocalName; | |
result[valueProperty] = element.Value; | |
// Add each attribute to the expando object | |
foreach (var attribute in element.Attributes()) | |
{ | |
result[attribute.Name.LocalName] = attribute.Value; | |
} | |
// Children element list (to be populated) and method to enumerate over them | |
var children = new List<dynamic>(); | |
result[elementsMethod] = new Func<IEnumerable<dynamic>>(() => children); | |
// Add each child node to the expando object and children list | |
foreach (var child in element.Elements()) | |
{ | |
var node = ToDynamic(child, nameProperty, valueProperty, elementsMethod); | |
children.Add(node); | |
var nodeName = (node as IDictionary<string, object>)[nameProperty].ToString(); | |
// If we haven't seen the node name before, add it as a property | |
if (!result.ContainsKey(nodeName)) | |
{ | |
result[nodeName] = node; | |
continue; | |
} | |
// If we've seen it once, replace with a list | |
if (!(result[nodeName] is List<dynamic>)) | |
{ | |
result[nodeName] = new List<dynamic>() { result[nodeName] }; | |
} | |
(result[nodeName] as List<dynamic>).Add(node); | |
} | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example: