XML数据存取封装

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XML数据存取封装相关的知识,希望对你有一定的参考价值。

公司目前用xml存储数据,不过之前是面向过程的,我觉得麻烦,于是抽象了一个数据存取操作的类,在一定程度上避免了重复造轮子..

此方法可以处理用于使用xml存储小量数据的项目,比如配置文件等

此方法对xml的操作需要将整个文件load到内存中,并且节点转Model时用了反射,这些是此方法比较明显的缺点,不过对于公司目前的开发效率提升还是比较明显的帮助的

 /// <summary>
    /// 基类
    /// 直接继承此类时表示不用文件单独存储的TEntity类型 只支持ModelToElement和PraseModel非文件操作辅助方法
    /// 如主类中存储子类,此时子类的操作类继承此类以辅助主类的存取
    /// </summary>
    public class Infrastructure<TEntity> where TEntity : class, new()
    {
        //主键列表
        public List<string> PrimaryKeys;
        //字段列表 随用随取
        public List<PropertyInfo> EntityPropertys;
        //节点名称 即tentity名称
        public readonly string ModelName;
        
        public Infrastructure()
        {
            EntityPropertys = typeof (TEntity).GetProperties().ToList();
            PrimaryKeys = GetPrimaryKeys();
            ModelName = typeof (TEntity).Name;
        }

        /// <summary>
        /// 把xml元素转成model 
        /// 自定义枚举类不被识别 以名称字符串对比
        /// </summary>
        /// <param name="element"></param>
        public TEntity PraseModel(XElement element)
        {
            TEntity result = new TEntity();

            if (element == null)
            {
                return null;
            }
            try
            {
                EntityPropertys.ForEach(ppt =>
                {
                    var node = element.Element(ppt.Name);
                    if (node == null)
                    {
                        return;
                    }
                    if (ppt.PropertyType == typeof (string))
                    {
                        ppt.SetValue(result, node.Value, null);
                    }
                    else if (ppt.PropertyType == typeof (bool))
                    {
                        ppt.SetValue(result, bool.Parse(node.Value), null);
                    }
                    else if (ppt.PropertyType == typeof (decimal))
                    {
                        ppt.SetValue(result, decimal.Parse(node.Value), null);
                    }
                    else if (ppt.PropertyType == typeof (ushort))
                    {
                        ppt.SetValue(result, ushort.Parse(node.Value), null);
                    }
                    else if (ppt.PropertyType == typeof (byte))
                    {
                        ppt.SetValue(result, byte.Parse(node.Value), null);
                    }
                    else if (ppt.PropertyType == typeof (uint))
                    {
                        ppt.SetValue(result, uint.Parse(node.Value), null);
                    }
                    else if (ppt.PropertyType.Name.Equals(typeof (SystemTypeEnum).Name))
                    {
                        ppt.SetValue(result, Enum.Parse(typeof (SystemTypeEnum), node.Value), null);
                    }
                    else if (ppt.PropertyType.Name.Equals(typeof (SexTypeEnum).Name))
                    {
                        ppt.SetValue(result, Enum.Parse(typeof (SexTypeEnum), node.Value.ToUpper()), null);
                    }
                    else if (ppt.PropertyType == typeof (double))
                    {
                        ppt.SetValue(result, double.Parse(node.Value), null);
                    }
                    else if (ppt.PropertyType.Name.Equals(typeof (AnimalFamilyEnum).Name))
                    {
                        ppt.SetValue(result, Enum.Parse(typeof (AnimalFamilyEnum), node.Value), null);
                    }
                    else if (ppt.PropertyType == typeof (DateTime))                     {
                        ppt.SetValue(result, DateTime.Parse(node.Value), null);
                    }
                });

                return result;
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return null;
            }
        }

        /// <summary>
        /// model转元素
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public XElement ModelToElement(TEntity model)
        {
            var modelDict = ModelToDict(model);
            return DictToXelement(modelDict);
        }

        /// <summary>
        /// 取主键列表
        /// </summary>
        private List<string> GetPrimaryKeys()
        {
            PrimaryKeys = new List<string>();
            EntityPropertys.ForEach(ppt =>
            {
                var attrs = ppt.GetCustomAttributes(true);
                if (!attrs.Any())
                {
                    return;
                }
                foreach (object attr in attrs)
                {
                    if ((attr as KeyAttribute) != null)
                    {
                        //标识了Key特性的字段
                        PrimaryKeys.Add(ppt.Name);
                    }
                }
            });

            return PrimaryKeys;
        }


        /// <summary>
        /// model转字典
        /// </summary>
        /// <param name="model"></param>
        public Dictionary<string, object> ModelToDict(TEntity model)
        {
            var dict = new Dictionary<string, object>();
            EntityPropertys.ForEach(ppt =>
            {
                dict[ppt.Name] = ppt.GetValue(model, null);
            });

            return dict;
        }


        /// <summary>
        /// 字典转元素
        /// </summary>
        /// <param name="dict"></param>
        public XElement DictToXelement(Dictionary<string, object> dict)
        {
            var result = new XElement(ModelName);
            foreach (var key in dict.Keys)
            {
                if (PrimaryKeys.Contains(key))
                {
                    //添加主键特性
                    result.SetAttributeValue(key, dict[key]);
                }

                var element = new XElement(key, dict[key]);

                result.Add(element);
            }

            return result;
        }


    }
/// <summary>
    /// 有单独xml文件存储的TEntity操作类需要继承该类
    /// </summary>
    public class Repository<TEntity> : Infrastructure<TEntity> where TEntity : class, new()
    {
        //数据存储的文档xml对象 
        public XElement XElement;

        //存储文件路径 ([相对路径/]文件名.ric)
        private readonly string _location;

        public Repository(string location)
        {
            if (!string.IsNullOrWhiteSpace(_location))
            {
                throw new Exception("FilePath Cann‘t Be Empty!");
            }

            _location = location;

            if (!File.Exists(location))
            {
                BuildXmlFile();
            }

            try
            {
                XElement = XElement.Load(location);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }


        /// <summary>
        /// 新增 有主键model新增主键相同的实例 不写入文件  判定写入成功
        /// </summary>
        /// <param name="entity">model实例</param>
        public virtual bool Insert(TEntity entity)
        {
            var elementDict = ModelToDict(entity);

            if (PrimaryKeys.Any() && HasModel(elementDict))
            {
                return true;
            }
            XElement.Add(DictToXelement(elementDict));

            return Save();
        }

        /// <summary>
        /// 新增多个 有主键model重复新增主键相同的实例 不写入文件  判定写入成功
        /// </summary>
        /// <param name="entitys">model集合</param>
        public virtual bool Insert(IEnumerable<TEntity> entitys)
        {

            foreach (TEntity entity in entitys)
            {
                var elementDict = ModelToDict(entity);

                if (PrimaryKeys.Any() && HasModel(elementDict))
                {
                    continue;
                }
                XElement.Add(DictToXelement(elementDict));
            }

            return Save();
        }

        /// <summary>
        /// 单主键删除
        /// </summary>
        /// <param name="id">主键值</param>
        public virtual bool Delete(object id)
        {
            var dict = new Dictionary<string, object>();
            if (PrimaryKeys.Any() && PrimaryKeys.Count == 1)
            {
                dict[PrimaryKeys[0]] = id;
            }
            else
            {
                return false;
            }
            var element = GetXElememt(dict);
            try
            {
                element.Remove();
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return false;
            }

            return Save();
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity">model实例</param>
        public virtual bool Delete(TEntity entity)
        {
            XElement element = ModelToElement(entity);
            try
            {
                element.Remove();
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return false;
            }

            return Save();
        }

        /// <summary>
        /// 删除多个
        /// </summary>
        /// <param name="entitys"></param>
        public virtual bool Delete(IEnumerable<TEntity> entitys)
        {
            try
            {
                foreach (TEntity entity in entitys)
                {
                    var element = ModelToElement(entity);
                    element.Remove();
                }
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return false;
            }

            return Save();
        }


        /// <summary>
        /// 修改 需model有主键定位需要修改的实例
        /// </summary>
        /// <param name="entity">model实例</param>
        public virtual bool Update(TEntity entity)
        {
            if (!PrimaryKeys.Any())
            {
                OtherOperation.WriteErrorIntoRecord("Delete failure! No primary key to locate element!");
                return false;
            }
            var dict = ModelToDict(entity);

            //用主键序列去文件中找到需要替换的元素
            var elementInFile = GetXElememt(dict);

            if (elementInFile == null)
            {
                //本地没有被替换的元素则改更新为新增
                return Insert(entity);
            }

            try
            {
                elementInFile.ReplaceWith(ModelToElement(entity));
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return false;
            }
            return Save();
        }

        /// <summary>
        /// 取一个
        /// </summary>
        /// <param name="id">主键值</param>
        /// <returns></returns>
        public virtual TEntity GetModel(object id)
        {
            var dict = new Dictionary<string, object>();
            if (PrimaryKeys.Any() && PrimaryKeys.Count == 1)
            {
                dict[PrimaryKeys[0]] = id;
            }
            else
            {
                return null;
            }
            try
            {
                var element = GetXElememt(dict);
                return PraseModel(element);
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return null;
            }
        }

        /// <summary>
        /// 取第一个 没有则返回null
        /// </summary>
        /// <returns></returns>
        public virtual TEntity GetFirstOrDefault()
        {
            try
            {
                return PraseModel(XElement.FirstNode as XElement);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 取全部
        /// </summary>
        public virtual List<TEntity> GetAllDatas()
        {
            var nodes = XElement.Nodes();
            var result = new List<TEntity>();

            foreach (XNode node in nodes)
            {
                var entity = PraseModel(node as XElement);
                if (entity != null)
                {
                    result.Add(entity);
                }
            }

            return result;
        }

        /// <summary>
        /// 保存修改 在此类内调用方法修改后直接保存  
        /// 覆写以上方法需主动调用此方法保存
        /// </summary>
        public virtual bool Save()
        {
            try
            {
                XElement.Save(_location);
            }
            catch (Exception e)
            {
                OtherOperation.WriteErrorIntoRecord(e.Message);
                return false;
            }
            return true;
        }


        /// <summary>
        /// 建立xml文档 写架构  (TEntity.Name).ric  架构可通过Model的字段特性申明具体属性  
        /// </summary>
        public void BuildXmlFile()
        {
            if (File.Exists(_location))
            {
                return;
            }
            var table = new DataTable(ModelName);

            EntityPropertys.ForEach(ppt =>
            {
                var dc = new DataColumn(ppt.Name, ppt.PropertyType)
                {
                    AllowDBNull = !PrimaryKeys.Contains(ppt.Name)
                };
                //AllowDBNull属性可以用特性申明
                if (ppt.PropertyType == typeof (string))
                {
                    dc.MaxLength = 50;
                }
                table.Columns.Add(dc);
            });

            table.WriteXml(_location, XmlWriteMode.WriteSchema);
        }

        /// <summary>
        /// 查找文件中是否有此元素
        /// </summary>
        /// <param name="dict"></param>
        public bool HasModel(Dictionary<string, object> dict)
        {
            return GetXElememt(dict) != null;
        }

        /// <summary>
        /// 根据字典取元素 有主键就按主键取 没主键就节点取 Default = null
        /// </summary>
        /// <param name="dict"></param>
        public XElement GetXElememt(Dictionary<string, object> dict)
        {

            XElement result;
            if (PrimaryKeys.Any() && PrimaryKeys.All(pk=>dict.Keys.Contains(pk)))
            {
                result = XElement.Elements().AsQueryable().FirstOrDefault(node =>
                    PrimaryKeys.All(d => node.Attribute(d) != null && node.Attribute(d).Value == (string) dict[d]));
            }
            else
            {
                result = XElement.Elements().AsQueryable().FirstOrDefault(node =>
                    dict.All(d => node.Element(d.Key) != null && node.Element(d.Key).Value == (string) d.Value));
            }

            return result;
        }

 

以上是关于XML数据存取封装的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

Mybatis中mapper.xml进行相关的封装

java大对象存取的简单实现的代码

回归 | js实用代码片段的封装与总结(持续更新中...)

在Tomcat的安装目录下conf目录下的server.xml文件中增加一个xml代码片段,该代码片段中每个属性的含义与用途