一、前言
根据指定的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>,后续也有些地方进行了改进,代码如下:
View Code
六、EntityMapper.ToDataTable<T>(List<T> entities)方法的单元测试
ToDataTable<T>(List<T> entities)方法的具体单元测试如下,仅仅是主要功能的测试:
View Code
七、总结
最近二个多月,忙死我了。这段时间转SIT测试了,终于又可以轻松一阵了,哈哈。这些随笔的内容都是上班时间之外写的,每次写的代码都做单元测试, 主要是避免出现显而易见的BUG,以及将代码积累并且更新到自己的框架中。接下来的一篇主要是如何将xml文本、xsl文本动态转换成html,这个花费 了本人一段时间,一直在摸索才整理出来的,主要是通过XslCompiledTransform.Transform(XmlReader input, XmlWriter results)来实现的,本人已经更新了几个版本了,这个应该是最终版本的,同时也是最精简的版本。