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>

本文中以上的代碼完全能夠對其進行相應的匹配。只不過上一篇隨筆中未對類的特性名稱和屬性的特性名稱進行考慮罷了,以后有時間再貼上改進后的代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM