XML反射解析
2016-06-03 14:14
429 查看
和同事对接一个接口,采用xml传输,从root节点到叶节点总共套了13层,导致对应实体类的编写困难,同时在xml操作6层后反序列化的时候总是会丢失部分信息,于是便想有没有什么办法更加简单地解析xml,花了一晚上时间,采用xpath加反射机制弄出了本文的成果,整体分为3块:实体类、配置类和解析器。
首先是定义一个helper工具类,作为解析器使用,核心思路就是根据传入的实体类和实体类对应的节点配置文件利用反射来获取值,遇到泛型的嵌套就递归获取下一层级的对象的值,代码里注释已经比较完整了,就不重复说了,需要注意的是目前的做法需要将帮助类、实体类、配置类放在同一个程序集内,因为目前使用的反射方式不支持跨程序集,有需要的可以自己修改:
(因为是为了满足遇到的问题写的,所以需要的朋友需要拉去自己改改才能用,例如在实体类中具有多个LIst<T>的情况下就需要修改代码)
然后定义一个实体类,需要说明的是多级嵌套的子级实体中需要配置ConfigName和ConfigNodeXPath两个属性,用来查找对应的配置类和xml节点:
最后是使用:
发现文中不妥之处欢迎提出宝贵意见,留言评论,共同进步,谢谢
原创内容,欢迎转载,但请注明出处:http://blog.csdn.net/huang461072830
首先是定义一个helper工具类,作为解析器使用,核心思路就是根据传入的实体类和实体类对应的节点配置文件利用反射来获取值,遇到泛型的嵌套就递归获取下一层级的对象的值,代码里注释已经比较完整了,就不重复说了,需要注意的是目前的做法需要将帮助类、实体类、配置类放在同一个程序集内,因为目前使用的反射方式不支持跨程序集,有需要的可以自己修改:
(因为是为了满足遇到的问题写的,所以需要的朋友需要拉去自己改改才能用,例如在实体类中具有多个LIst<T>的情况下就需要修改代码)
/// <summary> /// XML解析工具 /// </summary> public class XmlConvertUtility { /// <summary> /// 解析XML接口 /// </summary> /// <typeparam name="T">返回对象</typeparam> /// <param name="xml">返回的xml</param> /// <param name="rootNodeXPath">数据初始节点pxath表达式</param> /// <param name="config">配置类</param> /// <returns></returns> public List<T> ConvertXmlStringToObject<T>(string xml,string rootNodeXPath,object config)where T:new() { List<T> resultList = new List<T>(); try { if (string.IsNullOrWhiteSpace(xml)) throw new AggregateException("Xml不能为空"); XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); XmlNodeList nodes = doc.SelectNodes(rootNodeXPath); resultList = ConvertXmlToObject<T>(nodes, config); } catch (Exception ex) { throw ex; } return resultList; } /// <summary> /// 根据配置文件解析XML /// </summary> /// <typeparam name="T">返回对象,单返回对象作为List中的泛型类时需要配置一下两个参数 /// public string ConfigName { get { return "ProductItemXPathConfig"; } }//配置对象名称 /// public string ConfigNodeXPath { get { return "OrderSheet/orderDetailSet"; } }//XPath语句 /// </typeparam> /// <param name="pNodes">初始节点</param> /// <param name="xPathObject">Xpath表达式</param> /// <returns></returns> public List<T> ConvertXmlToObject<T>(XmlNodeList pNodes, object xPathObject) where T : new() { try { List<T> resultObjectList = new List<T>();//输出对象列表 T resultObject = new T();//输出对象 Type resultObjectType = resultObject.GetType();//输出对象类型 Type xPathObjectType = xPathObject.GetType();//配置对象类型 foreach (XmlNode node in pNodes)//遍历XML { resultObject = new T(); object objectPropertyValue; foreach (PropertyInfo xPathObjectProperty in xPathObjectType.GetProperties())//遍历配置对象 { string xPathObjectPropertyName = xPathObjectProperty.Name;//配置类属性名 if (string.IsNullOrWhiteSpace(xPathObjectPropertyName)) continue; Type objectPropertyType = resultObjectType.GetProperty(xPathObjectPropertyName).PropertyType;//获取输出对象类型 if (objectPropertyType.IsGenericType)//如果是泛型则递归加载下层 { //返回对象 Type childResultObjectType = objectPropertyType.GetGenericArguments().FirstOrDefault();//返回泛型中的对象 ConstructorInfo childResultObjectConstructor = childResultObjectType.GetConstructor(new Type[0]);//构造器 Object childResultObject = childResultObjectConstructor.Invoke(new Object[0]);//实例化配置对象 //XML,需要返回对象实例化后才能获得下面的值 PropertyInfo childXPthProperty = childResultObjectType.GetProperty("ConfigNodeXPath");//获取Xpath节点 if (childXPthProperty == null) throw new AggregateException("对象中具有List<T>时需配置ConfigNodeXPath属性"); string childXPathPropertyValue = childXPthProperty.GetValue(childResultObject, null).ToString(); if (string.IsNullOrWhiteSpace(childXPathPropertyValue)) throw new AggregateException("ConfigNodeXPath值不能为空"); XmlNodeList childPNode = node.SelectNodes(childXPathPropertyValue);//获取Xpath值 if (childPNode == null) continue; //配置对象 PropertyInfo childConfigObjectProperty = childResultObjectType.GetProperty("ConfigName");//获取Xpath配置节点 if (childConfigObjectProperty == null) throw new AggregateException("对象中具有List<T>时需配置ConfigName属性"); string childConfigObjectValue = childConfigObjectProperty.GetValue(childResultObject, null).ToString();//获取Xpath配置对象名 if (string.IsNullOrWhiteSpace(childConfigObjectValue)) throw new AggregateException("ConfigName值不能为空"); Type childConfigObjectType = Type.GetType(childResultObjectType.Assembly.GetName().Name + ".Config." + childConfigObjectValue, true); //获取配置对象类型 if (childConfigObjectType == null) throw new Exception("获取配置对象类型失败"); ConstructorInfo childConfigObjectConstructor = childConfigObjectType.GetConstructor(new Type[0]);//构造器 Object childConfigObject = childConfigObjectConstructor.Invoke(new Object[0]);//实例化配置对象 //递归执行 MethodInfo mi = this.GetType().GetMethod("ConvertXmlToObject").MakeGenericMethod(childResultObjectType);//委托执行递归 objectPropertyValue = mi.Invoke(this, new object[] { childPNode, childConfigObject });//递归获取下层List值 } else { string xPathObjectPropertyValue = xPathObjectProperty.GetValue(xPathObject, null).ToString();//获取配置对象属性值 if (string.IsNullOrWhiteSpace(xPathObjectPropertyValue))//判断配置对象属性值是否为空,如果是空则说明不映射 continue; if (resultObjectType.GetProperty(xPathObjectPropertyName) == null)//判断输出对象是否有对应名称的属性 continue; XmlNode objectNode = node.SelectSingleNode(xPathObjectPropertyValue); if (objectNode == null) continue; string resultObjectStringValue = objectNode.InnerText;//获取输出对象XML节点值 objectPropertyValue = Convert.ChangeType(resultObjectStringValue, objectPropertyType);//获取输出对象属性值 } resultObjectType.GetProperty(xPathObjectPropertyName).SetValue(resultObject, objectPropertyValue, null); } resultObjectList.Add(resultObject); } return resultObjectList; } catch (Exception ex) { throw ex; } } }
然后定义一个实体类,需要说明的是多级嵌套的子级实体中需要配置ConfigName和ConfigNodeXPath两个属性,用来查找对应的配置类和xml节点:
/// <summary> /// 用户类 /// </summary> public class User { public string Id{ get; set; } public string Name{ get; set; } public List<UserInfo> InfoList { get; set; } } public class UserInfo { public string ConfigName { get { return UserInfo.name; } } public string ConfigNodeXPath { get { return UserInfo.xpath; } } public string ChildName { get; set; } }最后定义配置类,用来配置每个属性对应的节点名称(xpath路径):
public class UserConfig { private string id= "id"; private string name= "name"; private List<UserInfo> infoList; public List<UserInfoConfig> InfoList { get { return infoList; } set { infoList= value; } } public string Id { get { return id; } set { id= value; } } public string Name { get { return name; } set { name= value; } } } public class UserInfoConfig { public static string name = "UserInfoConfig"; public static string xpath = "userDetailSet/UserInfo"; private string childName = "name"; public string ChildName { get { return childName ; } set { childName = value; } } }
最后是使用:
string xmlStr=@"<root> <body> <user> <id>S001</id> <name>张三</name> <userDetailSet clazz=\"com.UserInfo\"> <UserInfo> <name>李四</name> </UserInfo> <UserInfo> <name>王五</name> </UserInfo> </userDetailSet> </user> </body> </root>"; XmlConvertUtility xml = new XmlConvertUtility(); User test=xml.ConvertXmlStringToObject<User>(xmlStr, "//body/user", new UserConfig());</span>
发现文中不妥之处欢迎提出宝贵意见,留言评论,共同进步,谢谢
原创内容,欢迎转载,但请注明出处:http://blog.csdn.net/huang461072830
相关文章推荐
- 如何在 Linux/Windows/MacOS 上使用 .NET 进行开发
- Java反射随记
- c#调用COM组件
- XML 与 JSON 优劣对比
- 如何在 Linux 中安装微软的 .NET Core SDK
- AS3中的反射(速记) 分析
- As3.0 xml + Loader应用代码
- C#实现把指定数据写入串口
- C#动态创建button的方法
- C#中抽象方法与虚拟方法的区别
- c#中虚函数的相关使用方法
- C#实现给图片加水印的方法
- 网马生成器 MS Internet Explorer XML Parsing Buffer Overflow Exploit (vista) 0day
- C#使用加边法计算行列式的值
- C#实现多线程的同步方法实例分析
- ext读取两种结构的xml的代码
- C#中尾递归的使用、优化及编译器优化
- C#中的delegate委托类型基本学习教程
- C#实现子窗体与父窗体通信方法实例总结