Xml匹配为对象集合(两种不同的方式)

一、前言

上一篇随笔主要将实体转换成相应的Xml或者Xml对象,未考虑到属性的Attribute特性,以后有时间再整理一下。本文中的Xml匹配涉及到类的特性和属性的特性,并且对该类的匹配进行了相应的优化,尽量将反射引起的性能问题降低最低(其实,对于对象数量不是很多的Xml匹配,性能是可以忽略不计的)。

二、类图设计

 主要思路为:通过反射将与类名的节点匹配,然后匹配属性(属性特性名称或者属性名称)值,设计图如下所示:

 

类图中各个类的作用如下:

PropertyAttribute、ClassAttribute、StringExtension、FuncDictionary的作用详见XmlAttribute与实体的转换和匹配方案(附源码)

AttributeUtility主要用于获取类名和属性名称。
ReflectionUtility主要用于获取类型的属性对象与属性对应的特性名称的字典,为匹配进行优化处理。
XmlParser主要用于匹配Xml为实体对象。

 

三、具体实现

3.1 ReflectionUtility

该类主要用于获取某个类型的特性名称和相应的属性对象的字典。返回的类型为Dictionary<string, PropertyInfo>,其中Key为属性的特性名称,而非属性名称,Vaule为对应的属性对象。如此设计,主要是方便后续的操作。

主要方法为:
public static Dictionary<string, PropertyInfo> GetPropertyMapperDictionary<T>() where T : new(),
public static Dictionary<string, PropertyInfo> GetPropertyMapperDictionary(Type type) ,代码如下:
 1     public class ReflectionUtility
 2     {
 3         public static Dictionary<string, PropertyInfo> GetPropertyMapperDictionary<T>() where T : new()
 4         {
 5             return GetPropertyMapperDictionary(typeof(T));
 6         }
 7 
 8         public static Dictionary<string, PropertyInfo> GetPropertyMapperDictionary(Type type) 
 9         {
10             if (type == null)
11             {
12                 return null;
13             }
14 
15             List<PropertyInfo> properties = type.GetProperties().ToList();
16             var nameMapperDic = new Dictionary<string, PropertyInfo>();
17             string propertyAttributeName = null;
18 
19             foreach (PropertyInfo property in properties)
20             {
21                 propertyAttributeName = AttributeUtility.GetPropertyName(property);
22                 nameMapperDic.Add(propertyAttributeName, property);
23             }
24 
25             return nameMapperDic;
26         }
27 
28         public static IList<string> GetPropertyNames<T>() where T : new()
29         {
30             List<PropertyInfo> properties = typeof(T).GetProperties().ToList();
31             var propertyNames = new List<string>();
32 
33             foreach (PropertyInfo property in properties)
34             {
35                 propertyNames.Add(AttributeUtility.GetPropertyName(property));
36             }
37 
38             return propertyNames;
39         }
40     }

 

3.2 AttributeUtility

该类主要用于获取某个类型的类的特性名称和属性的特性名称。如果类的特性不存在,则返回类名。如果属性的特性名称不存在,则返回属性的名称。

主要方法为:
public static string GetClassName<T>() where T : new(),
public static string GetClassName(Type type) ,
public static string GetPropertyName(PropertyInfo property) ,代码如下:
 1     public class AttributeUtility
 2     {
 3         public static string GetClassName<T>() where T : new()
 4         {
 5             return GetClassName(typeof(T));
 6         }
 7 
 8         public static string GetClassName(Type type) 
 9         {
10             if (type == null)
11             {
12                 return string.Empty;
13             }
14 
15             string className = type.Name;
16             ClassAttribute[] attributes = type.GetCustomAttributes(
17                 typeof(ClassAttribute), falseas ClassAttribute[];
18 
19             if (attributes != null && attributes.Length > 0)
20             {
21                 if (!string.IsNullOrWhiteSpace(attributes[0].Name))
22                 {
23                     className = attributes[0].Name;
24                 }
25             }
26 
27             return className;
28         }
29 
30         public static string GetPropertyName(PropertyInfo property)
31         {
32             if (property == null)
33             {
34                 return string.Empty;
35             }
36 
37             string propertyName = property.Name;
38 
39             PropertyAttribute[] attributes = property.GetCustomAttributes(typeof(PropertyAttribute),
40                 falseas PropertyAttribute[];
41 
42             if (attributes != null && attributes.Length > 0)
43             {
44                 if (!string.IsNullOrWhiteSpace(attributes[0].Name))
45                 {
46                     propertyName = attributes[0].Name;
47                 }
48             }
49 
50             return propertyName;
51         }
52     }

 

3.2 XmlParser

该类主要通过两种不同的方式匹配Xml为实体对象集合,一种直接通过XmlReader进行只进读取匹配,另外一种通过XElement进行相应的匹配。

主要方法为:
public static IList<T> Parse<T>(string xmlContent) where T : new(),
public static IList<T> Parse<T>(XDocument document) where T : new() ,
public static IList<T> Parse<T>(IEnumerable<XElement> elements) where T : new(),
public static IList<T> Parse<T>(XmlReader xmlReader) where T : new() ,代码如下:
  1     public class XmlParser
  2     {
  3         public static IList<T> Parse<T>(string xmlContent) where T : new()
  4         {
  5             try
  6             {
  7                 if (string.IsNullOrWhiteSpace(xmlContent))
  8                 {
  9                     return new List<T>();
 10                 }
 11 
 12                 using (StringReader reader = new StringReader(xmlContent))
 13                 {
 14                     return Parse<T>(XmlReader.Create(reader));
 15                 }
 16             }
 17             catch
 18             {
 19                 return new List<T>();
 20             }
 21         }
 22 
 23         public static IList<T> Parse<T>(XDocument document) where T : new()
 24         {
 25             if (document == null)
 26             {
 27                 return new List<T>();
 28             }
 29 
 30             string className = AttributeUtility.GetClassName<T>();
 31             IEnumerable<XElement> elements = document.Root.Elements(className);
 32 
 33             return Parse<T>(elements);
 34         }
 35 
 36         public static IList<T> Parse<T>(IEnumerable<XElement> elements) where T : new()
 37         {
 38             if (elements == null || elements.Count() == 0)
 39             {
 40                 return new List<T>();
 41             }
 42 
 43             try
 44             {
 45                 var propertyDic = ReflectionUtility.GetPropertyMapperDictionary<T>();
 46                 List<T> entities = new List<T>();
 47                 IEnumerable<XElement> innerElements = null;
 48                 T entity = new T();
 49 
 50                 foreach (XElement element in elements)
 51                 {
 52                     entity = new T();
 53                     entities.Add(entity);
 54                     innerElements = element.Elements();
 55 
 56                     foreach (XElement innerElement in innerElements)
 57                     {
 58                         SetPropertyValue<T>(propertyDic, entity, innerElement.Name.ToString(), innerElement.Value);
 59                     }
 60                 }
 61 
 62                 return entities;
 63             }
 64             catch
 65             {
 66                 return new List<T>();
 67             }
 68         }
 69 
 70         public static IList<T> Parse<T>(XmlReader xmlReader) where T : new()
 71         {
 72             try
 73             {
 74                 if (xmlReader == null)
 75                 {
 76                     return new List<T>();
 77                 }
 78 
 79                 return ParseXmlReader<T>(xmlReader);
 80             }
 81             catch
 82             {
 83                 return new List<T>();
 84             }
 85         }
 86 
 87         private static IList<T> ParseXmlReader<T>(XmlReader xmlReader) where T : new()
 88         {
 89             List<PropertyInfo> properties = new List<PropertyInfo>(typeof(T).GetProperties());
 90             var propertyDic = ReflectionUtility.GetPropertyMapperDictionary<T>();
 91             string className = AttributeUtility.GetClassName<T>();
 92             IList<T> entities = new List<T>();
 93             T entity = new T();
 94             string lastElementName = null;
 95 
 96             while (xmlReader.Read())
 97             {
 98                 switch (xmlReader.NodeType)
 99                 {
100                     case XmlNodeType.Element:
101                         if (string.Equals(xmlReader.Name, className))
102                         {
103                             entity = new T();
104                             entities.Add(entity);
105                         }
106                         lastElementName = xmlReader.Name;
107                         break;
108                     case XmlNodeType.Text:
109                         SetPropertyValue<T>(propertyDic, entity, lastElementName, xmlReader.Value);
110                         break;
111                     default:
112                         break;
113                 }
114             }
115 
116             return entities;
117         }
118 
119         private static void SetPropertyValue<T>(Dictionary<string, PropertyInfo> propertyDic, T entity, string lastElementName, string value) where T : new()
120         {
121             if (!string.IsNullOrWhiteSpace(lastElementName) && propertyDic.ContainsKey(lastElementName))
122             {
123                 PropertyInfo currentProperty = propertyDic[lastElementName];
124                 if (currentProperty != null && currentProperty.CanWrite)
125                 {
126                     object invokeResult = new FuncDictionary().DynamicInvoke(currentProperty.PropertyType, value);
127                     currentProperty.SetValue(entity, invokeResult, null);
128                 }
129             }
130         }
131     }

 

以上两种不同的方式匹配Xml,都是通过var propertyDic = ReflectionUtility.GetPropertyMapperDictionary<T>();来对反射所引起的性能进行了相关的优化。对于多个实体的匹配,只需要执行一次映射获取到属性特性的名称与对应属性的字典,其后的匹配以该字典来进行操作。

 

、总结

与上一篇随笔将对象集合转换为Xml恰恰相反,对于如下类似格式的Xml:

View Code
<MapperInfoItem>
  <DefaultName>MapperInfoItemIndex0</DefaultName>
  <CreatedTime>2012/1/6 19:24:34</CreatedTime>
  <IsActive>True</IsActive>
  <DefaultValue>10</DefaultValue>
  <Percent>27</Percent>
  <TargetUrl>www.codeplex.com?Id=0</TargetUrl>
</MapperInfoItem>

本文中以上的代码完全能够对其进行相应的匹配。只不过上一篇随笔中未对类的特性名称和属性的特性名称进行考虑罢了,以后有时间再贴上改进后的代码。

posted @ 2012-02-19 11:38  jasen.kin  阅读(...)  评论(...编辑  收藏