• 如何将List<T>转换相应的Html(xsl动态转换)(一)


    一、前言

    根据指定的xsl样式将List<T>转换相应的Html,其中涉及到怎样将List<T>转换成DataTable,如何将xml文本、xsl样式文本动态转换成html以及如何设置以及控制xsl样式。主要步骤如下:

    步骤一、将List<T>转换成DataTable

    步骤二、将Xml与Xsl动态转换成Html

    步骤三、设置以及控制Xsl的内容样式。

    以上的三个步骤本人将以此顺序介绍相关的内容,分别对应相关的随笔,因为本人上班的时候不能上网以及时间上的问题,所以才将该文章分3次来写。

    二、类图设计

    以上的内容涉及的类图虽然很简单,但是本人还是花了不少时间的来实现具体功能,代码质量还是可以保证的。EntityMapper负责将List<T>转换成DataTable(目前先将就着用这个,还有一个比较复杂的,涉及的东西比较多,此处不会讲解,以后有时间再写),XslTransform负责将xml文本、xsl文本转换成html,XslTransformFacade外观模式封装其中的细节,如下:

     

    三、将List<T>转换成DataTable,再转换成xml的具体实现

    这里主要是个思路的问题,先将List<T>转换成DataTable,然后将DataTable添加到DataSet中,最后通过DataSet的GetXml()方法获取Xml内容。这里思路正确的话,实现不是很复杂。先看下XslTransformFacade类,基本思路都封装在该类中:

     1     public class XslTransformFacade
     2     {
     3         public static string ToHtml<T>(List<T> entities,string xslText) where T : new()
     4         {
     5             if (ValidateArgs(entities,xslText))
     6             {
     7                 return string.Empty;
     8             }
     9 
    10             string xmlText= GetXmlText<T>(entities);
    11 
    12             using (XslTransform xslTransform = new XslTransform())
    13             {
    14                 return xslTransform.Transfer(xmlText, xslText);
    15             }
    16         }
    17 
    18         private static bool ValidateArgs<T>(List<T> entities, string xslText)
    19         {
    20             return entities == null || entities.Count == 0 
    21                 || string.IsNullOrWhiteSpace(xslText);
    22         }
    23 
    24         private static string GetXmlText<T>(List<T> entities) where T : new()
    25         {
    26             using (DataSet dataSet = new DataSet("DataSet"))
    27             {
    28                 DataTable dataTable = EntityMapper.ToDataTable<T>(entities);
    29                 dataSet.Tables.Add(dataTable);
    30                 return dataSet.GetXml();
    31             }
    32         }
    33     }

    这一步骤主要是通过GetXmlText<T>(List<T> entities)方法来实现的。EntityMapper.ToDataTable<T>(entities)方法将在下面介绍。生成的Xml如下(示例):

    -<DataSet>
    - <MapperInfo>
      
    <Name>MapperInfoIndex0</Name> 
      
    <CreatedTime>2011-05-24T00:27:23.734375+08:00</CreatedTime> 
      
    <IsActive>true</IsActive> 
      
    <Value>0</Value> 
      
    <Percent>0</Percent> 
      
    <TargetUrl>www.codeplex.com?Id=0</TargetUrl> 
      
    </MapperInfo>
    - <MapperInfo>
      
    <Name>MapperInfoIndex1</Name> 
      
    <CreatedTime>2011-05-24T00:27:23.734375+08:00</CreatedTime> 
      
    <IsActive>false</IsActive> 
      
    <Value>1</Value> 
      
    <TargetUrl>www.codeplex.com?Id=1</TargetUrl> 
      
    </MapperInfo>
    -</DataSet>

    其次第12-15行主要是将xmlText、xslText转换成html,这将在后续的文章中介绍具体实现:

    12             using (XslTransform xslTransform = new XslTransform())
    13             {
    14                 return xslTransform.Transfer(xmlText, xslText);
    15             }

    四、将List<T>转换成DataTable

    这里主要是通过反射将List<T>转换成DataTable。其中需要设置DataTable的DataColumnCollection集合以及设置DataRowCollection集合。具体代码如下:

     1     public sealed class EntityMapper 
     2     {
     3         public static DataTable ToDataTable<T>(List<T> entities) where T : new()
     4         {
     5             if (entities == null || entities.Count == 0)
     6             {
     7                 return new DataTable();
     8             }
     9 
    10             using (DataTable dataTable = new DataTable(typeof(T).Name))
    11             {
    12                 PropertyInfo[] properties = typeof(T).GetProperties();
    13 
    14                 SetColumnsType(properties, dataTable);
    15                 SetTableContent<T>(entities, properties, dataTable);
    16 
    17                 return dataTable;
    18             }
    19         }
    20 
    21         private static void SetTableContent<T>(List<T> entities, 
    22             PropertyInfo[] properties, DataTable dataTable)
    23         {
    24             foreach (T entity in entities)
    25             {
    26                 AddTableRowsAndContent<T>(properties, entity,dataTable);
    27             }
    28         }
    29 
    30         private static void AddTableRowsAndContent<T>(PropertyInfo[] properties,
    31             T entity, DataTable dataTable)
    32         {
    33             DataRow newRow = dataTable.NewRow();
    34             foreach (PropertyInfo propertyInfo in properties)
    35             {
    36                 if (!CanGetPropertyValue(propertyInfo,dataTable))
    37                 {
    38                     continue;
    39                 }
    40 
    41                 try
    42                 {
    43                     object objValue = propertyInfo.GetValue(entity, null);
    44                     newRow[propertyInfo.Name] = objValue ?? DBNull.Value;
    45                 }
    46                 finally 
    47                 {
    48                 }
    49             }
    50 
    51             dataTable.Rows.Add(newRow);
    52         }
    53 
    54         private static bool CanGetPropertyValue(PropertyInfo propertyInfo, DataTable dataTable)
    55         {
    56             return propertyInfo.CanRead && 
    57                 dataTable.Columns.Contains(propertyInfo.Name);
    58         }
    59 
    60         private static void SetColumnsType(PropertyInfo[] properties, DataTable dataTable)
    61         {
    62             Type colType = null;
    63 
    64             foreach (PropertyInfo propInfo in properties)
    65             {
    66                 if (propInfo.PropertyType.IsGenericType)
    67                 {
    68                     colType = Nullable.GetUnderlyingType(propInfo.PropertyType);
    69                 }
    70                 else
    71                 {
    72                     colType = propInfo.PropertyType;
    73                 }
    74 
    75                 if (colType.FullName.StartsWith("System"))
    76                 {
    77                     dataTable.Columns.Add(propInfo.Name, colType);
    78                 }
    79             }
    80         }
    81      }

    这里主要的操作步骤为以下2行代码:

    14                 SetColumnsType(properties, dataTable);
    15                 SetTableContent<T>(entities, properties, dataTable);

    14行设置列的类型,15行设置DataRowCollection的DataRow内容,对于上面的代码,再多的解释都是无用的,看具体代码就行了。

     

    其中需要解释一下的就是54-58行:

    54         private static bool CanGetPropertyValue(PropertyInfo propertyInfo, DataTable dataTable)
    55         {
    56             return propertyInfo.CanRead && 
    57                 dataTable.Columns.Contains(propertyInfo.Name);
    58         }
    因为当属性不可读,并且DataColumnCollection不包行该属性名时,赋值可能会抛出异常的。

    其次还提一下第10行:

    10             using (DataTable dataTable = new DataTable(typeof(T).Name))

    这里用using来释放资源,主要是使代码中不存在任何警告,警告有时候使系统奔溃也有可能。否则进行代码分析的时候会出现警告信息,如下图所示:

     

    五、DataTable 转换成List<T> (这个是附加的,与此主题无关,但是也是EntityMapper 的一部分)

    虽然以前写了一篇《 将DataRow转换成相应的对象(通用以及泛型操作) 》 ,但是并不是将DataTable 转换成List<T>,后续也有些地方进行了改进,代码如下:

    public static List<T> ToEntities<T>(DataTable dataTable) where T : new()
            {
                List
    <T> entities = new List<T>();
                
    if (dataTable == null || dataTable.Rows == null
                    
    || dataTable.Rows.Count == 0)
                {
                    
    return entities;
                }

                
    foreach (DataRow dataRow in dataTable.Rows)
                {
                    entities.Add(ToEntity
    <T>(dataRow));
                }

                
    return entities;
            }

            
    public static T ToEntity<T>(DataRow dataRow) where T : new()
            {
                
    if (dataRow == null)
                {
                    
    return default(T);
                }

                T item 
    = Activator.CreateInstance<T>();
                CopyToEntity(item, dataRow);

                
    return item;
            }

            
    public static void CopyToEntity(object entity, DataRow dataRow)
            {
                
    if (entity == null || dataRow == null)
                {
                    
    return;
                }
                PropertyInfo[] propertyInfos 
    = entity.GetType().GetProperties();

                
    foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    
    if (!CanSetPropertyValue(propertyInfo, dataRow))
                    {
                        
    continue;
                    }

                    
    try
                    {
                        
    if (dataRow[propertyInfo.Name] is DBNull)
                        {
                            propertyInfo.SetValue(entity, 
    nullnull);
                            
    continue;
                        }
                        SetPropertyValue(entity, dataRow, propertyInfo);
                    }
                    
    finally
                    {
                    }
                }
            }

            
    private static bool CanSetPropertyValue(PropertyInfo propertyInfo,
                DataRow dataRow)
            {
                
    return propertyInfo.CanWrite && 
                    dataRow.Table.Columns.Contains(propertyInfo.Name); 
            }

            
    private static void SetPropertyValue(object entity,
                DataRow dataRow, PropertyInfo propertyInfo)
            {
                
    if (propertyInfo.PropertyType == typeof(DateTime?||
                    propertyInfo.PropertyType 
    == typeof(DateTime))
                {
                    DateTime date 
    = DateTime.MaxValue;
                    DateTime.TryParse(dataRow[propertyInfo.Name].ToString(),
                        CultureInfo.CurrentCulture, DateTimeStyles.None, 
    out date);

                    propertyInfo.SetValue(entity, date, 
    null);
                }
                
    else
                {
                    propertyInfo.SetValue(entity, dataRow[propertyInfo.Name], 
    null);
                }
            }

    六、EntityMapper.ToDataTable<T>(List<T> entities)方法的单元测试

    ToDataTable<T>(List<T> entities)方法的具体单元测试如下,仅仅是主要功能的测试:

    public class EntityMapperTest
     2     {
     3         [TestMethod()]
     4         public void ToDataTableTest()
     5         {
     6             List<MapperInfo> entities = CreateMapperInfos(9);
     7             DataTable result = EntityMapper.ToDataTable<MapperInfo>(entities);
     8             Assert.IsNotNull(result);
     9             Assert.IsNotNull(result.Rows);
    10             Assert.AreEqual(9, result.Rows.Count);
    11             int index = 0;
    12             foreach (DataRow dataRow in result.Rows)
    13             {
    14                 Assert.AreEqual(dataRow["Name"], 
    15                     string.Concat("MapperInfoIndex", index.ToString()));
    16                 Assert.AreEqual(dataRow["IsActive"], index % 2 == 0 ? true : false);
    17                 Assert.AreEqual(dataRow["Value"], index);
    18                 Assert.IsNotNull(dataRow["CreatedTime"]);
    19                 Assert.AreEqual(dataRow["Percent"], DBNull.Value);
    20                 index++;
    21                 
    22             }
    23         }
    24 
    25         private List<MapperInfo> CreateMapperInfos(int count)
    26         {
    27             List<MapperInfo> entities = new List<MapperInfo>();
    28             for (int index = 0; index < count; index++)
    29             {
    30                 entities.Add(new MapperInfo()
    31                 {
    32                     Name = string.Concat("MapperInfoIndex", index.ToString()),
    33                     IsActive = (index % 2 == 0 ? true : false),
    34                     CreatedTime = DateTime.Now,
    35                     Value = index
    36                 });
    37             }
    38 
    39             return entities;
    40         }
    41     }

    七、总结

    最近二个多月,忙死我了。这段时间转SIT测试了,终于又可以轻松一阵了,哈哈。这些随笔的内容都是上班时间之外写的,每次写的代码都做单元测试,主要是避免出现显而易见的BUG,以及将代码积累并且更新到自己的框架中。接下来的一篇主要是如何将xml文本、xsl文本动态转换成html,这个花费了本人一段时间,一直在摸索才整理出来的,主要是通过XslCompiledTransform.Transform(XmlReader input, XmlWriter results)来实现的,本人已经更新了几个版本了,这个应该是最终版本的,同时也是最精简的版本。

  • 相关阅读:
    Web开发快速上手
    前端概述
    Python语言进阶
    图像和办公文档处理
    网络编程
    进程和线程
    正则表达式
    面向对象进阶
    面向对象
    js 获取指定时间上月26 ,
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2059313.html
Copyright © 2020-2023  润新知