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); } } }