protected override object GetValueFromXml(XElement root, XName name, PropertyInfo prop, bool useExactName)
        {
            bool isAttribute = false;

            //Check for the DeserializeAs attribute on the property
            DeserializeAsAttribute options = prop.GetAttribute <DeserializeAsAttribute>();

            if (options != null)
            {
                name        = options.Name ?? name;
                isAttribute = options.Attribute;
            }

            if (!isAttribute)
            {
                return(base.GetValueFromXml(root, name, prop, useExactName));
            }

            XAttribute attributeVal = GetAttributeByName(root, name, useExactName);

            return(attributeVal != null ? attributeVal.Value : base.GetValueFromXml(root, name, prop, useExactName));
        }
        protected virtual object Map(object x, XElement root)
        {
            Type objType = x.GetType();

            PropertyInfo[] props = objType.GetProperties();
            bool           deserializeFromContentAttributeAlreadyUsed = false;

            foreach (var prop in props)
            {
                var type         = prop.PropertyType.GetTypeInfo();
                var typeIsPublic = type.IsPublic || type.IsNestedPublic;

                if (!typeIsPublic || !prop.CanWrite)
                {
                    continue;
                }

                bool  deserializeFromContent   = false;
                bool  isNameDefinedInAttribute = false;
                XName name       = null;
                var   attributes = prop.GetCustomAttributes(typeof(DeserializeAsAttribute), false);

                if (attributes.Any())
                {
                    DeserializeAsAttribute attribute = (DeserializeAsAttribute)attributes.First();

                    name = attribute.Name.AsNamespaced(Namespace);
                    isNameDefinedInAttribute = !string.IsNullOrEmpty(name?.LocalName);

                    deserializeFromContent = attribute.Content;

                    if (deserializeFromContentAttributeAlreadyUsed && deserializeFromContent)
                    {
                        throw new ArgumentException("Class cannot have two properties marked with " +
                                                    "SerializeAs(Content = true) attribute.");
                    }

                    deserializeFromContentAttributeAlreadyUsed |= deserializeFromContent;
                }

                if (name == null)
                {
                    name = prop.Name.AsNamespaced(Namespace);
                }

                var value = GetValueFromXml(root, name, prop, isNameDefinedInAttribute);

                if (value == null)
                {
                    // special case for text content node
                    if (deserializeFromContent)
                    {
                        var textNode = root.Nodes().FirstOrDefault(n => n is XText);
                        if (textNode != null)
                        {
                            value = ((XText)textNode).Value;
                            prop.SetValue(x, value, null);
                        }
                        continue;
                    }

                    // special case for inline list items
                    if (type.IsGenericType)
                    {
                        var genericType = type.GetGenericArguments()[0];
                        var first       = GetElementByName(root, genericType.Name);
                        var list        = (IList)Activator.CreateInstance(type.AsType());

                        if (first != null && root != null)
                        {
                            var elements = root.Elements(first.Name);

                            PopulateListFromElements(genericType, elements, list);
                        }

                        prop.SetValue(x, list, null);
                    }
                    continue;
                }

                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    // if the value is empty, set the property to null...
                    if (string.IsNullOrEmpty(value.ToString()))
                    {
                        prop.SetValue(x, null, null);
                        continue;
                    }

                    type = type.GetGenericArguments()[0].GetTypeInfo();
                }

                var asType = type.AsType();
                if (asType == typeof(bool))
                {
                    var toConvert = value.ToString()
                                    .ToLower();

                    prop.SetValue(x, XmlConvert.ToBoolean(toConvert), null);
                }
                else if (type.IsPrimitive)
                {
                    prop.SetValue(x, value.ChangeType(asType, Culture), null);
                }
                else if (type.IsEnum)
                {
                    var converted = type.AsType().FindEnumValue(value.ToString(), Culture);

                    prop.SetValue(x, converted, null);
                }
                else if (asType == typeof(Uri))
                {
                    var uri = new Uri(value.ToString(), UriKind.RelativeOrAbsolute);

                    prop.SetValue(x, uri, null);
                }
                else if (asType == typeof(string))
                {
                    prop.SetValue(x, value, null);
                }
                else if (asType == typeof(DateTime))
                {
                    value = DateFormat.HasValue()
                        ? DateTime.ParseExact(value.ToString(), DateFormat, Culture)
                        : DateTime.Parse(value.ToString(), Culture);

                    prop.SetValue(x, value, null);
                }
                else if (asType == typeof(DateTimeOffset))
                {
                    var toConvert = value.ToString();

                    if (string.IsNullOrEmpty(toConvert))
                    {
                        continue;
                    }

                    DateTimeOffset deserialisedValue;

                    try
                    {
                        deserialisedValue = XmlConvert.ToDateTimeOffset(toConvert);
                        prop.SetValue(x, deserialisedValue, null);
                    }
                    catch (Exception)
                    {
                        if (TryGetFromString(toConvert, out var result, asType))
                        {
                            prop.SetValue(x, result, null);
                        }
                        else
                        {
                            //fallback to parse
                            deserialisedValue = DateTimeOffset.Parse(toConvert);
                            prop.SetValue(x, deserialisedValue, null);
                        }
                    }
                }