예제 #1
0
        /// <summary>
        /// Convert an XElement to the assigned type using mappings provided by Mappable/Mapping attributes
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="element"></param>
        /// <returns></returns>
        public static bool TryDeserialize <T>(XElement element, T obj, DeserializeCaution caution = DeserializeCaution.CheckElementName, string rootMappableName = null)
        {
            Type     type     = obj.GetType();
            Mappable mappable = type.GetCustomAttribute(typeof(Mappable)) as Mappable;

            if (mappable == null)
            {
                throw new MappableException("Object type is not Mappable");
            }

            if (rootMappableName != null)
            {
                mappable.Name = rootMappableName;
            }

            if ((element.Name.LocalName != mappable.Name) && (caution == DeserializeCaution.CheckElementName))
            {
                return(false);
            }

            var members = ((object[])type.GetFields()).Union(type.GetProperties());


            var fields     = type.GetFields().Where(f => f.GetCustomAttribute(typeof(Mapping)) != null);
            var properties = type.GetProperties().Where(p => p.GetCustomAttribute(typeof(Mapping)) != null);

            // Assign members
            foreach (var member in members.Where(m => GetCustomAttribute(m, typeof(Mapping)) != null))
            {
                Mapping mapping = (Mapping)GetCustomAttribute(member, typeof(Mapping));

                string value = element.Attribute(mapping.Name)?.Value;
                if (value == null)
                {
                    if (mapping.Optional == false)
                    {
                        throw new MappableException($"Mapped property {mapping.Name} was not found in XElement '{element}'");
                    }
                }
                else
                {
                    object convertedValue = null;
                    try
                    {
                        convertedValue = ConvertIn(member, element.Attribute(mapping.Name)?.Value);
                    }
                    catch
                    {
                        convertedValue = default;
                    }
                    SetValue(member, obj, convertedValue);
                }
            }

            // get simple lists
            var lists = members.Where(m => GetCustomAttribute(m, typeof(ListMapping)) != null);

            foreach (var listMember in lists)
            {
                ListMapping listMapping   = (ListMapping)GetCustomAttribute(listMember, typeof(ListMapping));
                Mappable    childMappable = (Mappable)listMapping.ChildType.GetCustomAttribute(typeof(Mappable));
                if (childMappable == null)
                {
                    throw new MappableException("Children of ListMappings should be Mappables");
                }

                IList children = GetValue(listMember, obj) as IList;
                if (children == null)
                {
                    throw new MappableException($"List '{listMapping.Name}' cannot be serialized: is not collection or is not initialized");
                }
                XElement listElm = element.Descendants().FirstOrDefault(e => e.Name.LocalName == listMapping.Name);
                if (listElm == null)
                {
                    if (!listMapping.Optional)
                    {
                        throw new MappableException("Required list is missing");
                    }
                    else
                    {
                        continue;
                    }
                }
                foreach (var child in listElm?.XPathSelectElements(childMappable.Name) ?? new List <XElement>())
                {
                    object newChil = Activator.CreateInstance(listMapping.ChildType);
                    if (!TryDeserialize(child, newChil, caution))
                    {
                        throw new MappableException($"Could not assign value from element {listElm}");
                    }

                    children.Add(newChil);
                }
            }

            // assign ValueMapping
            var valueMapping = members.FirstOrDefault(m => GetCustomAttribute(m, typeof(ValueMapping)) != null);

            if (valueMapping != null)
            {
                SetValue(valueMapping, obj, ConvertIn(valueMapping, element.Value));
            }

            // Assign children
            var childMembers = members.Where(m => GetCustomAttribute(m, typeof(ChildMapping)) != null);

            foreach (var member in childMembers)
            {
                ChildMapping mapping = (ChildMapping)GetCustomAttribute(member, typeof(ChildMapping));

                if (mapping.ChildType == null)
                {
                    // maps only one value
                    object childObj = Activator.CreateInstance(MemberType(member));

                    // rename mapping if necessary
                    bool     overrideMappableName = false;
                    Mappable childObjMappable     = (Mappable)childObj.GetType().GetCustomAttribute(typeof(Mappable));
                    if (childObjMappable != null && childObjMappable.Name == null)
                    {
                        overrideMappableName = true;
                    }


                    XElement child = element.Descendants(mapping.Name).FirstOrDefault();
                    if (child == null)
                    {
                        if (!mapping.Optional)
                        {
                            return(false);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    if (!TryDeserialize(child, childObj, caution, rootMappableName: overrideMappableName?mapping.Name : null))
                    {
                        return(false);
                    }
                    SetValue(member, obj, childObj);
                }
                else
                {
                    // maps many values into a list
                    Mappable childTypeMapping = (Mappable)mapping.ChildType.GetCustomAttribute(typeof(Mappable));
                    IList    children         = GetValue(member, obj) as IList;
                    if (children == null)
                    {
                        throw new MappableException($"Object member {member} is not initilaized or is not a collection");
                    }
                    IEnumerable <XElement> elmChildren = element.Descendants().Where(elm => elm.Name.LocalName == childTypeMapping.Name);
                    foreach (var child in elmChildren)
                    {
                        object childObj = Activator.CreateInstance(mapping.ChildType);
                        if (!TryDeserialize(child, childObj, caution))
                        {
                            return(false);
                        }
                        children.Add(childObj);
                    }
                }
            }

            // assign simple value children (non-Mappable children mapped to members of model)
            foreach (var member in members.Where(m => GetCustomAttribute(m, typeof(ValueChildMapping)) != null))
            {
                ValueChildMapping mapping = (ValueChildMapping)GetCustomAttribute(member, typeof(ValueChildMapping));
                XElement          prop    = element.Descendants(mapping.Name).FirstOrDefault();
                if (prop == null)
                {
                    if (!mapping.Optional)
                    {
                        throw new MappableException($"Missing required property '{mapping.Name}' from XElement '{prop}'");
                    }
                    else
                    {
                        continue;
                    }
                }
                SetValue(member, obj, ConvertIn(member, prop.Value));
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Serializes a class into an XElement using the Mappable/Mapping attributes.
        /// Only public properties may be serialized
        /// </summary>
        /// <param name="serializable"></param>
        /// <returns></returns>
        public static XElement Serialize(object serializable, string rootElementName = null)
        {
            if (serializable == null)
            {
                return(null);
            }

            Type t = serializable.GetType();

            Attribute[] attrs = Attribute.GetCustomAttributes(t);
            Mappable    l     = (Mappable)attrs.FirstOrDefault(a => a is Mappable);

            if (l == null)
            {
                return(null);
            }

            if (rootElementName != null)
            {
                l.Name = rootElementName;
            }

            // make the element
            XElement elm = new XElement(l.Name);

            var members = ((object[])t.GetFields()).Union(t.GetProperties());

            // assign the attributes
            foreach (var member in members.Where(m => GetCustomAttribute(m, typeof(Mapping)) != null))
            {
                Mapping           trait      = (Mapping)GetCustomAttribute(member, typeof(Mapping));
                MappingConversion conversion = (MappingConversion)GetCustomAttribute(member, typeof(MappingConversion));
                object            value      = ConvertOut(member, serializable);

                if (value == null && trait.Optional)
                {
                    continue;
                }

                XAttribute attr = new XAttribute(trait.Name, value ?? "");
                elm.Add(attr);
            }

            // assign values to simple lists
            var lists = members.Where(m => GetCustomAttribute(m, typeof(ListMapping)) != null);

            foreach (var listMember in lists)
            {
                ListMapping listMapping = (ListMapping)GetCustomAttribute(listMember, typeof(ListMapping));
                IList       children    = GetValue(listMember, serializable) as IList;
                if (children == null)
                {
                    throw new MappableException($"List '{listMapping.Name}' cannot be serialized: is not collection or is null");
                }
                XElement listElm = new XElement(listMapping.Name);
                foreach (var child in children)
                {
                    listElm.Add(Serialize(child));
                }
                elm.Add(listElm);
            }

            // assign a value to the XElement
            var valueMapping = members.FirstOrDefault(m => GetCustomAttribute(m, typeof(ValueMapping)) != null);

            if (valueMapping != null)
            {
                string val = ConvertOut(valueMapping, serializable);
                if (val != null)
                {
                    elm.Value = val;
                }
            }

            // assign the children
            foreach (var member in members.Where(m => GetCustomAttribute(m, typeof(ChildMapping)) != null))
            {
                ChildMapping mapping = (ChildMapping)GetCustomAttribute(member, typeof(ChildMapping));
                if (mapping.ChildType == null)
                {
                    Mappable childMappable = (Mappable)MemberType(member).GetCustomAttribute(typeof(Mappable));

                    // maps only one value
                    XElement childElm = Serialize(GetValue(member, serializable), rootElementName: childMappable.Name == null ? mapping.Name : null);
                    if (childElm != null)
                    {
                        elm.Add(childElm);
                    }
                }
                else
                {
                    // mapped to many values
                    IList children = GetValue(member, serializable) as IList;
                    if (children == null)
                    {
                        return(null);
                    }

                    foreach (var child in children)
                    {
                        XElement childElm = Serialize(child);
                        elm.Add(childElm);
                    }
                }
            }

            // assign simple value children (non-Mappable children mapped to members of model)
            foreach (var member in members.Where(m => GetCustomAttribute(m, typeof(ValueChildMapping)) != null))
            {
                ValueChildMapping mapping     = (ValueChildMapping)GetCustomAttribute(member, typeof(ValueChildMapping));
                XElement          simpleChild = new XElement(mapping.Name);
                string            val         = ConvertOut(member, serializable);

                if (val != null)
                {
                    simpleChild.Value = val;
                    elm.Add(simpleChild);
                }
            }


            return(elm);
        }